def setUpClass(cls): '''creating prerequisites for installing a role; setUpClass occurs ONCE whereas setUp occurs with every method tested.''' # class data for easy viewing: role_dir, role_tar, role_name, role_req, role_path if os.path.exists("./delete_me"): shutil.rmtree("./delete_me") # creating framework for a role gc = GalaxyCLI(args=["init"]) with patch('sys.argv', ["-c", "--offline", "delete_me"]): gc.parse() gc.run() cls.role_dir = "./delete_me" cls.role_name = "delete_me" # making a temp dir for role installation cls.role_path = os.path.join(tempfile.mkdtemp(), "roles") if not os.path.isdir(cls.role_path): os.makedirs(cls.role_path) # creating a tar file name for class data cls.role_tar = './delete_me.tar.gz' cls.makeTar(cls.role_tar, cls.role_dir) # creating a temp file with installation requirements cls.role_req = './delete_me_requirements.yml' fd = open(cls.role_req, "w") fd.write("- 'src': '%s'\n 'name': '%s'\n 'path': '%s'" % (cls.role_tar, cls.role_name, cls.role_path)) fd.close()
def test_exit_without_ignore_with_flag(self): ''' tests that GalaxyCLI exits without the error specified if the --ignore-errors flag is used ''' # testing with --ignore-errors flag gc = GalaxyCLI(args=["ansible-galaxy", "install", "--server=None", "fake_role_name", "--ignore-errors"]) gc.parse() with patch.object(ansible.utils.display.Display, "display", return_value=None) as mocked_display: gc.run() self.assertTrue(mocked_display.called_once_with("- downloading role 'fake_role_name', owned by "))
def test_display_galaxy_info(self): gc = GalaxyCLI(args=self.default_args) galaxy_info = {} role_info = {'name': 'some_role_name', 'galaxy_info': galaxy_info} display_result = gc._display_role_info(role_info) if display_result.find('\n\tgalaxy_info:') == -1: self.fail('Expected galaxy_info to be indented once')
def test_exit_without_ignore_without_flag(self): ''' tests that GalaxyCLI exits with the error specified if the --ignore-errors flag is not used ''' gc = GalaxyCLI(args=["install", "--server=None", "fake_role_name"]) gc.parse() with patch.object(ansible.utils.display.Display, "display", return_value=None) as mocked_display: # testing that error expected is raised self.assertRaises(AnsibleError, gc.run) self.assertTrue(mocked_display.called_once_with("- downloading role 'fake_role_name', owned by "))
def test_run(self): ''' verifies that the GalaxyCLI object's api is created and that execute() is called. ''' gc = GalaxyCLI(args=["ansible-galaxy", "install", "--ignore-errors", "imaginary_role"]) gc.parse() with patch.object(ansible.cli.CLI, "execute", return_value=None) as mock_ex: with patch.object(ansible.cli.CLI, "run", return_value=None) as mock_run: gc.run() # testing self.assertEqual(mock_run.call_count, 1) self.assertTrue(isinstance(gc.api, ansible.galaxy.api.GalaxyAPI)) self.assertEqual(mock_ex.call_count, 1)
def test_parse_search(self): ''' testing the options parswer when the action 'search' is given ''' gc = GalaxyCLI(args=["ansible-galaxy", "search"]) self.run_parse_common(gc, "search") self.assertEqual(gc.options.platforms, None) self.assertEqual(gc.options.galaxy_tags, None) self.assertEqual(gc.options.author, None)
def test_validate_certs_with_server_url(global_ignore_certs, monkeypatch): cli_args = [ 'ansible-galaxy', 'collection', 'install', 'namespace.collection:1.0.0', '-s', 'https://galaxy.ansible.com' ] if global_ignore_certs: cli_args.append('--ignore-certs') galaxy_cli = GalaxyCLI(args=cli_args) mock_execute_install = MagicMock() monkeypatch.setattr(galaxy_cli, '_execute_install_collection', mock_execute_install) galaxy_cli.run() assert len(galaxy_cli.api_servers) == 1 assert galaxy_cli.api_servers[0].validate_certs is not global_ignore_certs
def call_galaxy_cli(args): orig = co.GlobalCLIArgs._Singleton__instance co.GlobalCLIArgs._Singleton__instance = None try: GalaxyCLI(args=['ansible-galaxy', 'collection'] + args).run() finally: co.GlobalCLIArgs._Singleton__instance = orig
def test_call_GalaxyCLI_with_implicit_role(execute_verify): galaxy_args = ['ansible-galaxy', 'verify', 'namespace.implicit_role'] with pytest.raises(SystemExit): GalaxyCLI(args=galaxy_args).run() assert not execute_verify.called
def test_execute_verify(mock_verify_collections): GalaxyCLI(args=[ 'ansible-galaxy', 'collection', 'verify', 'namespace.collection:1.0.4', '--ignore-certs', '-p', '~/.ansible', '--ignore-errors', '--server', 'http://galaxy-dev.com', ]).run() assert mock_verify_collections.call_count == 1 requirements, search_paths, galaxy_apis, ignore_errors = mock_verify_collections.call_args[ 0] assert [('%s.%s' % (r.namespace, r.name), r.ver, r.src, r.type) for r in requirements] == [('namespace.collection', '1.0.4', None, 'galaxy')] for install_path in search_paths: assert install_path.endswith('ansible_collections') assert galaxy_apis[0].api_server == 'http://galaxy-dev.com' assert ignore_errors is True
def test_collection_install_custom_server(collection_install): mock_install, mock_warning, output_dir = collection_install galaxy_args = ['ansible-galaxy', 'collection', 'install', 'namespace.collection', '--collections-path', output_dir, '--server', 'https://galaxy-dev.ansible.com'] GalaxyCLI(args=galaxy_args).run() assert mock_install.call_args[0][2] == ['https://galaxy-dev.ansible.com']
def test_collection_install_ignore(collection_install): mock_install, mock_warning, output_dir = collection_install galaxy_args = ['ansible-galaxy', 'collection', 'install', 'namespace.collection', '--collections-path', output_dir, '--ignore-errors'] GalaxyCLI(args=galaxy_args).run() assert mock_install.call_args[0][4] is True
def test_collection_install_force_deps(collection_install): mock_install, mock_warning, output_dir = collection_install galaxy_args = ['ansible-galaxy', 'collection', 'install', 'namespace.collection', '--collections-path', output_dir, '--force-with-deps'] GalaxyCLI(args=galaxy_args).run() assert mock_install.call_args[0][7] is True
def test_parse_import(self): ''' testing the options parser when the action 'import' is given ''' gc = GalaxyCLI(args=["ansible-galaxy", "import"]) self.run_parse_common(gc, "import") self.assertEqual(gc.options.wait, True) self.assertEqual(gc.options.reference, None) self.assertEqual(gc.options.check_status, False) self.assertEqual(gc.options.verbosity, 0)
def test_call_GalaxyCLI(execute_verify): galaxy_args = [ 'ansible-galaxy', 'collection', 'verify', 'namespace.collection' ] GalaxyCLI(args=galaxy_args).run() assert execute_verify.call_count == 1
def test_execute_remove(self): # installing role gc = GalaxyCLI(args=["ansible-galaxy", "install", "-p", self.role_path, "-r", self.role_req, '--force']) gc.parse() gc.run() # location where the role was installed role_file = os.path.join(self.role_path, self.role_name) # removing role gc = GalaxyCLI(args=["ansible-galaxy", "remove", role_file, self.role_name]) gc.parse() gc.run() # testing role was removed removed_role = not os.path.exists(role_file) self.assertTrue(removed_role)
def test_build_requirement_from_name_missing(galaxy_server, monkeypatch, tmp_path_factory): mock_open = MagicMock() mock_open.return_value = [] monkeypatch.setattr(galaxy_server, 'get_collection_versions', mock_open) test_dir = to_bytes(tmp_path_factory.mktemp('test-ÅÑŚÌβŁÈ Collections Input')) concrete_artifact_cm = collection.concrete_artifact_manager.ConcreteArtifactsManager(test_dir, validate_certs=False) cli = GalaxyCLI(args=['ansible-galaxy', 'collection', 'install', 'namespace.collection:>1.0.1']) requirements = cli._require_one_of_collections_requirements( ['namespace.collection'], None, artifacts_manager=concrete_artifact_cm )['collections'] expected = "Failed to resolve the requested dependencies map. Could not satisfy the following requirements:\n* namespace.collection:* (direct request)" with pytest.raises(AnsibleError, match=re.escape(expected)): collection._resolve_depenency_map(requirements, [galaxy_server, galaxy_server], concrete_artifact_cm, None, False, True, False, False)
def test_parse_setup(self): ''' testing the options parser when the action 'setup' is given ''' gc = GalaxyCLI(args=["ansible-galaxy", "setup"]) self.run_parse_common(gc, "setup") self.assertEqual(gc.options.verbosity, 0) self.assertEqual(gc.options.remove_id, None) self.assertEqual(gc.options.setup_list, False)
def test_execute_list_collection_no_valid_paths(mocker, capsys): """Test listing collections when no valid paths are given""" cliargs() mocker.patch('os.path.exists', return_value=True) mocker.patch('os.path.isdir', return_value=False) gc = GalaxyCLI(['ansible-galaxy', 'collection', 'list']) with pytest.raises(AnsibleOptionsError, match=r'None of the provided paths were usable.'): gc.execute_list_collection() out, err = capsys.readouterr() assert '[WARNING]: - the configured path' in err assert 'exists, but it is not a directory.' in err
def test_run(self): ''' verifies that the GalaxyCLI object's api is created and that execute() is called. ''' gc = GalaxyCLI(args=["install"]) with patch('sys.argv', ["-c", "-v", '--ignore-errors', 'imaginary_role']): galaxy_parser = gc.parse() with patch.object(ansible.cli.CLI, "execute", return_value=None) as mock_ex: with patch.object(ansible.cli.CLI, "run", return_value=None) as mock_run: gc.run() # testing self.assertEqual(mock_run.call_count, 1) self.assertTrue( isinstance(gc.api, ansible.galaxy.api.GalaxyAPI)) self.assertEqual(mock_ex.call_count, 1)
def test_parse_install(self): ''' testing the options parser when the action 'install' is given ''' gc = GalaxyCLI(args=["ansible-galaxy", "install"]) self.run_parse_common(gc, "install") self.assertEqual(gc.options.ignore_errors, False) self.assertEqual(gc.options.no_deps, False) self.assertEqual(gc.options.role_file, None) self.assertEqual(gc.options.force, False)
def test_parse_import(self): ''' testing the options parser when the action 'import' is given ''' gc = GalaxyCLI(args=["ansible-galaxy", "import"]) self.run_parse_common(gc, "import") self.assertEqual(context.CLIARGS['wait'], True) self.assertEqual(context.CLIARGS['reference'], None) self.assertEqual(context.CLIARGS['check_status'], False) self.assertEqual(context.CLIARGS['verbosity'], 0)
def test_parse_setup(self): ''' testing the options parser when the action 'setup' is given ''' gc = GalaxyCLI(args=["ansible-galaxy", "setup"]) self.run_parse_common(gc, "setup") self.assertEqual(context.CLIARGS['verbosity'], 0) self.assertEqual(context.CLIARGS['remove_id'], None) self.assertEqual(context.CLIARGS['setup_list'], False)
def test_parse_install(self): ''' testing the options parser when the action 'install' is given ''' gc = GalaxyCLI(args=["ansible-galaxy", "install"]) self.run_parse_common(gc, "install") self.assertEqual(context.CLIARGS['ignore_errors'], False) self.assertEqual(context.CLIARGS['no_deps'], False) self.assertEqual(context.CLIARGS['role_file'], None) self.assertEqual(context.CLIARGS['force'], False)
def test_build_requirement_from_name_401_unauthorized(galaxy_server, monkeypatch, tmp_path_factory): mock_open = MagicMock() mock_open.side_effect = api.GalaxyError(urllib_error.HTTPError('https://galaxy.server.com', 401, 'msg', {}, StringIO()), "error") monkeypatch.setattr(galaxy_server, 'get_collection_versions', mock_open) test_dir = to_bytes(tmp_path_factory.mktemp('test-ÅÑŚÌβŁÈ Collections Input')) concrete_artifact_cm = collection.concrete_artifact_manager.ConcreteArtifactsManager(test_dir, validate_certs=False) cli = GalaxyCLI(args=['ansible-galaxy', 'collection', 'install', 'namespace.collection:>1.0.1']) requirements = cli._require_one_of_collections_requirements( ['namespace.collection'], None, artifacts_manager=concrete_artifact_cm )['collections'] expected = "error (HTTP Code: 401, Message: msg)" with pytest.raises(api.GalaxyError, match=re.escape(expected)): collection._resolve_depenency_map(requirements, [galaxy_server, galaxy_server], concrete_artifact_cm, None, False, False, False, False)
def test_collection_install_no_name_and_requirements_fail(collection_install): test_path = collection_install[2] expected = 'You must specify a collection name or a requirements file.' with pytest.raises(AnsibleError, match=expected): GalaxyCLI(args=[ 'ansible-galaxy', 'collection', 'install', '--collections-path', test_path ]).run()
def test_collection_install_name_and_requirements_fail(collection_install): test_path = collection_install[2] expected = 'The positional collection_name arg and --requirements-file are mutually exclusive.' with pytest.raises(AnsibleError, match=expected): GalaxyCLI(args=[ 'ansible-galaxy', 'collection', 'install', 'namespace.collection', '--collections-path', test_path, '--requirements-file', test_path ]).run()
def collection_artifact(collection_skeleton, tmp_path_factory): ''' Creates a collection artifact tarball that is ready to be published and installed ''' output_dir = to_text(tmp_path_factory.mktemp('test-ÅÑŚÌβŁÈ Output')) # Because we call GalaxyCLI in collection_skeleton we need to reset the singleton back to None so it uses the new # args, we reset the original args once it is done. orig_cli_args = co.GlobalCLIArgs._Singleton__instance try: co.GlobalCLIArgs._Singleton__instance = None galaxy_args = [ 'ansible-galaxy', 'collection', 'build', collection_skeleton, '--output-path', output_dir ] gc = GalaxyCLI(args=galaxy_args) gc.run() yield output_dir finally: co.GlobalCLIArgs._Singleton__instance = orig_cli_args
def test_exit_without_ignore(self): ''' tests that GalaxyCLI exits with the error specified unless the --ignore-errors flag is used ''' gc = GalaxyCLI(args=["install"]) # testing without --ignore-errors flag with patch('sys.argv', ["-c", "fake_role_name"]): galaxy_parser = gc.parse() with patch.object(ansible.utils.display.Display, "display", return_value=None) as mocked_display: # testing that error expected is raised self.assertRaises(AnsibleError, gc.run) self.assertTrue(mocked_display.called_once_with("- downloading role 'fake_role_name', owned by ")) # testing with --ignore-errors flag with patch('sys.argv', ["-c", "fake_role_name", "--ignore-errors"]): galalxy_parser = gc.parse() with patch.object(ansible.utils.display.Display, "display", return_value=None) as mocked_display: # testing that error expected is not raised with --ignore-errors flag in use gc.run() self.assertTrue(mocked_display.called_once_with("- downloading role 'fake_role_name', owned by "))
def test_execute_remove(self): # installing role gc = GalaxyCLI(args=["install", "--offline", "-p", self.role_path, "-r", self.role_req]) galaxy_parser = gc.parse() gc.run() # checking that installation worked role_file = os.path.join(self.role_path, self.role_name) self.assertTrue(os.path.exists(role_file)) # removing role gc = GalaxyCLI(args=["remove", "-c", "-p", self.role_path, self.role_name]) galaxy_parser = gc.parse() super(GalaxyCLI, gc).run() gc.api = ansible.galaxy.api.GalaxyAPI(gc.galaxy) completed_task = gc.execute_remove() # testing role was removed self.assertTrue(completed_task == 0) self.assertTrue(not os.path.exists(role_file))
def test_require_one_of_collections_requirements_with_collections(): cli = GalaxyCLI(args=[ 'ansible-galaxy', 'collection', 'verify', 'namespace1.collection1', 'namespace2.collection1:1.0.0' ]) collections = ( 'namespace1.collection1', 'namespace2.collection1:1.0.0', ) requirements = cli._require_one_of_collections_requirements( collections, '')['collections'] req_tuples = [( '%s.%s' % (req.namespace, req.name), req.ver, req.src, req.type, ) for req in requirements] assert req_tuples == [('namespace1.collection1', '*', None, 'galaxy'), ('namespace2.collection1', '1.0.0', None, 'galaxy')]
def test_exit_without_ignore(self): ''' tests that GalaxyCLI exits with the error specified unless the --ignore-errors flag is used ''' gc = GalaxyCLI(args=["install"]) # testing without --ignore-errors flag with patch('sys.argv', ["-c", "fake_role_name"]): galaxy_parser = gc.parse() with patch.object(ansible.utils.display.Display, "display", return_value=None) as mocked_display: # testing that error expected is raised self.assertRaises(AnsibleError, gc.run) self.assertTrue( mocked_display.called_once_with( "- downloading role 'fake_role_name', owned by ")) # testing with --ignore-errors flag with patch('sys.argv', ["-c", "fake_role_name", "--ignore-errors"]): galalxy_parser = gc.parse() with patch.object(ansible.utils.display.Display, "display", return_value=None) as mocked_display: # testing that error expected is not raised with --ignore-errors flag in use gc.run() self.assertTrue( mocked_display.called_once_with( "- downloading role 'fake_role_name', owned by "))
def _install_roles_from_file(plugin_path): # Ansible Galaxy - install roles from file for req_file in ['requirements.yml', 'requirements.yaml']: galaxy_reqs_file = os.path.join(plugin_path, req_file) if not os.path.isfile(galaxy_reqs_file): continue LOG.debug( "Installing Ansible Galaxy " "requirements from file... ({})".format(galaxy_reqs_file)) from ansible.cli.galaxy import GalaxyCLI from ansible.errors import AnsibleError glxy_cli_params = [ 'ansible-galaxy', 'role', 'install', '-r', galaxy_reqs_file ] if InfraredPluginManager._is_collection_requirements( galaxy_reqs_file): glxy_cli_params[1] = 'collection' LOG.debug("Ansible Galaxy command: {}".format(glxy_cli_params)) glxy_cli = GalaxyCLI(glxy_cli_params) glxy_cli.parse() LOG.debug( "Trying to install Ansible Galaxy required " "collection 5 times to circumvent potential network issues") try: glxy_cli.run() except AnsibleError as e: raise IRGalaxyRoleInstallFailedException( "Failed to install Ansible Galaxy requirements, aborting! Error: {}" .format(e)) else: LOG.debug("Ansible Galaxy requirements files weren't found.")
def setUpRole(cls, role_name, galaxy_args=None, skeleton_path=None): if galaxy_args is None: galaxy_args = [] if skeleton_path is not None: cls.role_skeleton_path = skeleton_path galaxy_args += ['--role-skeleton', skeleton_path] # Make temp directory for testing cls.test_dir = tempfile.mkdtemp() if not os.path.isdir(cls.test_dir): os.makedirs(cls.test_dir) cls.role_dir = os.path.join(cls.test_dir, role_name) cls.role_name = role_name # create role using default skeleton gc = GalaxyCLI(args=['ansible-galaxy', 'init', '-c', '--offline'] + galaxy_args + ['--init-path', cls.test_dir, cls.role_name]) gc.parse() gc.run() cls.gc = gc if skeleton_path is None: cls.role_skeleton_path = gc.galaxy.default_role_skeleton_path
def test_build_requirement_from_name(galaxy_server, monkeypatch, tmp_path_factory): mock_get_versions = MagicMock() mock_get_versions.return_value = ['2.1.9', '2.1.10'] monkeypatch.setattr(galaxy_server, 'get_collection_versions', mock_get_versions) mock_version_metadata = MagicMock(namespace='namespace', name='collection', version='2.1.10', artifact_sha256='', dependencies={}) monkeypatch.setattr(api.GalaxyAPI, 'get_collection_version_metadata', mock_version_metadata) test_dir = to_bytes( tmp_path_factory.mktemp('test-ÅÑŚÌβŁÈ Collections Input')) concrete_artifact_cm = collection.concrete_artifact_manager.ConcreteArtifactsManager( test_dir, validate_certs=False) collections = ['namespace.collection'] requirements_file = None cli = GalaxyCLI( args=['ansible-galaxy', 'collection', 'install', collections[0]]) requirements = cli._require_one_of_collections_requirements( collections, requirements_file, artifacts_manager=concrete_artifact_cm)['collections'] actual = collection._resolve_depenency_map(requirements, [galaxy_server], concrete_artifact_cm, None, True, False, False)['namespace.collection'] assert actual.namespace == u'namespace' assert actual.name == u'collection' assert actual.ver == u'2.1.10' assert actual.src == galaxy_server assert mock_get_versions.call_count == 1 assert mock_get_versions.mock_calls[0][1] == ('namespace', 'collection')
def test_validate_certs(global_ignore_certs, server_config, monkeypatch): get_plugin_options = MagicMock(side_effect=server_config) monkeypatch.setattr(C.config, 'get_plugin_options', get_plugin_options) cli_args = [ 'ansible-galaxy', 'collection', 'install', 'namespace.collection:1.0.0', ] if global_ignore_certs: cli_args.append('--ignore-certs') galaxy_cli = GalaxyCLI(args=cli_args) mock_execute_install = MagicMock() monkeypatch.setattr(galaxy_cli, '_execute_install_collection', mock_execute_install) galaxy_cli.run() assert galaxy_cli.api_servers[0].validate_certs is False assert galaxy_cli.api_servers[1].validate_certs is True assert galaxy_cli.api_servers[2].validate_certs is not global_ignore_certs
inventory_path = os.path.join(tmpdir, 'inventory') if (options.no_ansible_galaxy and options.no_ansible): ansible_vars_path = None inventory_path = None vars_file = conf.write_ansible_vars( dstname=ansible_vars_path) inventory_file = conf.write_ansible_inventory(dstname=inventory_path) exit_code = 0 if not options.no_ansible_galaxy: print("[+] launching ansible-galaxy") default_opts = ["ansible-galaxy"] default_opts += ["install"] default_opts += ["-r", "ansible-requirements.yml"] default_opts += ["--force"] galaxy_cli = GalaxyCLI(default_opts) galaxy_cli.parse() exit_code = galaxy_cli.run() if exit_code: clean_and_exit(tmpdir, exit_code) if not options.no_ansible: print("[+] launching ansible-playbook") default_opts = ["ansible-playbook"] default_opts += ["-i", "default_groups"] default_opts += ["-i", inventory_file] default_opts += ["-e", "@{}".format(vars_file)] if '-u' not in options.ansible_args: default_opts += ["-u", "vagrant"] if options.offline: default_opts += [
def test_display_min(self): gc = GalaxyCLI(args=self.default_args) role_info = {'name': 'some_role_name'} display_result = gc._display_role_info(role_info) self.assertTrue(display_result.find('some_role_name') >-1)
def install_ansible_requirements(): cmd = ['ansible-galaxy', 'install', '-r', 'ansible-requirements.yml'] cli = GalaxyCLI(cmd) sys.argv = cmd cli.parse() return cli.run()