Example #1
0
class TestConfigureAuthentication(MAASTestCase):
    def setUp(self):
        super().setUp()
        self.maas_bin_path = "snap-path/bin/maas-region"
        self.mock_subprocess = self.patch(init, "subprocess")
        self.mock_environ = patch.dict(init.os.environ, {"SNAP": "snap-path"},
                                       clear=True)
        self.mock_environ.start()
        self.parser = ArgumentParser()
        init.add_rbac_options(self.parser)
        init.add_candid_options(self.parser)

    def tearDown(self):
        self.mock_subprocess.stop()
        self.mock_environ.stop()
        super().tearDown()

    def test_no_options(self):
        options = self.parser.parse_args([])
        init.configure_authentication(options)
        [config_call] = self.mock_subprocess.mock_calls
        method, args, kwargs = config_call
        self.assertEqual("call", method)
        self.assertEqual(([self.maas_bin_path, "configauth"], ), args)
        self.assertEqual({}, kwargs)

    def test_rbac_url(self):
        config_auth_args = ["--rbac-url", "http://rrbac.example.com/"]
        options = self.parser.parse_args(config_auth_args)
        init.configure_authentication(options)
        [config_call] = self.mock_subprocess.mock_calls
        method, args, kwargs = config_call
        self.assertEqual("call", method)
        self.assertEqual(
            ([self.maas_bin_path, "configauth"] + config_auth_args, ), args)
        self.assertEqual({}, kwargs)

    def test_rbac_service_name(self):
        config_auth_args = ["--rbac-service-name", "mymaas"]
        options = self.parser.parse_args(config_auth_args)
        init.configure_authentication(options)
        [config_call] = self.mock_subprocess.mock_calls
        method, args, kwargs = config_call
        self.assertEqual("call", method)
        self.assertEqual(
            ([self.maas_bin_path, "configauth"] + config_auth_args, ), args)
        self.assertEqual({}, kwargs)

    def test_candid_agent_file(self):
        _, agent_file_path = tempfile.mkstemp()
        self.addCleanup(os.remove, agent_file_path)
        config_auth_args = ["--candid-agent-file", agent_file_path]
        options = self.parser.parse_args(config_auth_args)
        init.configure_authentication(options)
        [config_call] = self.mock_subprocess.mock_calls
        method, args, kwargs = config_call
        self.assertEqual("call", method)
        self.assertEqual(
            ([self.maas_bin_path, "configauth"] + config_auth_args, ), args)
        self.assertEqual({}, kwargs)
Example #2
0
class TestCreateAdminOptions(MAASTestCase):

    def setUp(self):
        super().setUp()
        self.parser = ArgumentParser()
        init.add_create_admin_options(self.parser)

    def test_create_admin_options_empty(self):
        options = self.parser.parse_args([])
        self.assertIsNone(options.admin_username)
        self.assertIsNone(options.admin_password)
        self.assertIsNone(options.admin_email)
        self.assertIsNone(options.admin_ssh_import)

    def test_create_admin_options_username(self):
        options = self.parser.parse_args(
            ['--admin-username', 'my-username'])
        self.assertEqual('my-username', options.admin_username)

    def test_create_admin_options_password(self):
        options = self.parser.parse_args(['--admin-password', 'my-password'])
        self.assertEqual('my-password', options.admin_password)

    def test_create_admin_options_email(self):
        options = self.parser.parse_args(['--admin-email', '*****@*****.**'])
        self.assertEqual('*****@*****.**', options.admin_email)

    def test_create_admin_options_ssh_import(self):
        options = self.parser.parse_args(['--admin-ssh-import', 'lp:me'])
        self.assertEqual('lp:me', options.admin_ssh_import)
Example #3
0
class TestCmdInit(MAASTestCase):
    def setUp(self):
        super().setUp()
        self.parser = ArgumentParser()
        self.cmd = cli.cmd_init(self.parser)
        self.maas_region_path = init.get_maas_region_bin_path()
        self.call_mock = self.patch(init.subprocess, "call")
        self.check_output_mock = self.patch(init.subprocess, "check_output")
        self.check_output_mock.return_value = json.dumps(
            {"external_auth_url": ""})
        # avoid printouts
        self.mock_stdout = self.patch(init.sys, "stdout", StringIO())
        self.mock_stderr = self.patch(init.sys, "stderr", StringIO())

    def test_defaults(self):
        options = self.parser.parse_args([])
        self.assertFalse(options.skip_admin)
        self.assertIsNone(options.admin_username)
        self.assertIsNone(options.admin_password)
        self.assertIsNone(options.admin_email)
        self.assertIsNone(options.admin_ssh_import)
        self.assertIsNone(options.candid_agent_file)
        self.assertIsNone(options.rbac_url)

    def test_init_maas_calls_subcommands(self):
        options = self.parser.parse_args([])
        self.cmd(options)
        configauth_call, createadmin_call = self.call_mock.mock_calls
        _, args1, kwargs1 = configauth_call
        _, args2, kwargs2 = createadmin_call
        self.assertEqual(([self.maas_region_path, "configauth"], ), args1)
        self.assertEqual({}, kwargs1)
        self.assertEqual(([self.maas_region_path, "createadmin"], ), args2)
        self.assertEqual({}, kwargs2)
Example #4
0
class TestAddCandidOptions(MAASTestCase):

    def setUp(self):
        super().setUp()
        self.parser = ArgumentParser()
        init.add_candid_options(self.parser)
        self.mock_stderr = self.patch(init.sys, "stderr", StringIO())

    def test_add_candid_options_empty(self):
        options = self.parser.parse_args([])
        self.assertIsNone(options.candid_agent_file)

    def test_add_candid_options_candid_domain(self):
        options = self.parser.parse_args(
            ['--candid-domain', 'mydomain'])
        self.assertEqual('mydomain', options.candid_domain)

    def test_add_candid_options_candid_agent_file(self):
        options = self.parser.parse_args(['--candid-agent-file', 'agent.file'])
        self.assertEqual(options.candid_agent_file, 'agent.file')

    def test_add_candid_options_candid_admin_group(self):
        options = self.parser.parse_args(
            ['--candid-admin-group', 'admins'])
        self.assertEqual('admins', options.candid_admin_group)
Example #5
0
class TestAddIdmOptions(MAASTestCase):
    def setUp(self):
        super().setUp()
        self.parser = ArgumentParser()
        init.add_idm_options(self.parser)

    def test_add_idm_options_empty(self):
        options = self.parser.parse_args([])
        self.assertIsNone(options.idm_url)
        self.assertIsNone(options.idm_user)
        self.assertIsNone(options.idm_key)
        self.assertIsNone(options.idm_agent_file)

    def test_add_idm_options_idm_url(self):
        options = self.parser.parse_args(
            ['--idm-url', 'http://idm.example.com/'])
        self.assertEqual('http://idm.example.com/', options.idm_url)

    def test_add_idm_options_idm_user(self):
        options = self.parser.parse_args(['--idm-user', 'my-user'])
        self.assertEqual('my-user', options.idm_user)

    def test_add_idm_options_idm_key(self):
        options = self.parser.parse_args(['--idm-key', 'my-key'])
        self.assertEqual('my-key', options.idm_key)

    def test_add_idm_options_idm_agent_file(self):
        fd, agent_file_name = tempfile.mkstemp()
        self.addCleanup(os.remove, agent_file_name)

        os.write(fd, b'my-agent-file-content')
        os.close(fd)
        options = self.parser.parse_args(['--idm-agent-file', agent_file_name])
        self.assertEqual('my-agent-file-content',
                         options.idm_agent_file.read())
Example #6
0
class TestAddRBACOptions(MAASTestCase):
    def setUp(self):
        super().setUp()
        self.parser = ArgumentParser()
        init.add_rbac_options(self.parser)

    def test_empty(self):
        options = self.parser.parse_args([])
        self.assertIsNone(options.rbac_url)

    def test_rbac_url(self):
        options = self.parser.parse_args(
            ['--rbac-url', 'http://rbac.example.com/'])
        self.assertEqual('http://rbac.example.com/', options.rbac_url)
Example #7
0
class TestCmdConfig(MAASTestCase):
    def setUp(self):
        super().setUp()
        self.parser = ArgumentParser()
        self.cmd = snappy.cmd_config(self.parser)
        self.patch(os, "getuid").return_value = 0
        snap_common = self.make_dir()
        snap_data = self.make_dir()
        self.useFixture(EnvironmentVariableFixture("SNAP_COMMON", snap_common))
        self.useFixture(EnvironmentVariableFixture("SNAP_DATA", snap_data))

    def test_show(self):
        # Regression test for LP:1892868
        stdout = io.StringIO()
        self.patch(sys, "stdout", stdout)
        options = self.parser.parse_args([])
        self.assertIsNone(self.cmd(options))
        self.assertEqual(stdout.getvalue(), "Mode: none\n")

    def test_enable_debugging(self):
        mock_maas_configuration = self.patch(snappy, "MAASConfiguration")
        mock_sighup_supervisord = self.patch(snappy, "sighup_supervisord")
        options = self.parser.parse_args(["--enable-debug"])
        stdout = io.StringIO()
        self.patch(sys, "stdout", stdout)

        self.cmd(options)
        mock_maas_configuration().update.assert_called_once_with(
            {"debug": True}
        )
        # After config is changed, services are restarted
        self.assertEqual(stdout.getvalue(), "Stopping services\n")
        mock_sighup_supervisord.assert_called_once_with()

    def test_reenable_debugging(self):
        mock_maas_configuration = self.patch(snappy, "MAASConfiguration")
        config_manager = mock_maas_configuration()
        mock_sighup_supervisord = self.patch(snappy, "sighup_supervisord")
        options = self.parser.parse_args(["--enable-debug"])
        stdout = io.StringIO()
        self.patch(sys, "stdout", stdout)

        # Simulate the value already being enabled
        current_config = config_manager.get()
        current_config.get.side_effect = {"debug": True}.__getitem__

        self.cmd(options)
        config_manager.update.assert_not_called()
        self.assertEqual(stdout.getvalue(), "")
        mock_sighup_supervisord.assert_not_called()
Example #8
0
 def test_requires_root(self):
     parser = ArgumentParser()
     cmd = snappy.cmd_status(parser)
     self.patch(os, "getuid").return_value = 1000
     error = self.assertRaises(SystemExit, cmd, parser.parse_args([]))
     self.assertEqual(str(error),
                      "The 'status' command must be run by root.")
Example #9
0
 def test_cmd_configure_supervisord(self):
     self.patch(snappy, "get_current_mode").return_value = "region+rack"
     mock_render_supervisord = self.patch(snappy, "render_supervisord")
     mock_sighup_supervisord = self.patch(snappy, "sighup_supervisord")
     parser = ArgumentParser()
     cmd = snappy.cmd_reconfigure_supervisord(parser)
     cmd(parser.parse_args([]))
     mock_render_supervisord.assert_called_once_with("region+rack")
     mock_sighup_supervisord.assert_called_once()
Example #10
0
class TestAddRBACOptions(MAASTestCase):
    def setUp(self):
        super().setUp()
        self.parser = ArgumentParser()
        init.add_rbac_options(self.parser)

    def test_empty(self):
        options = self.parser.parse_args([])
        self.assertIsNone(options.rbac_url)

    def test_rbac_url(self):
        options = self.parser.parse_args(
            ["--rbac-url", "http://rbac.example.com/"])
        self.assertEqual("http://rbac.example.com/", options.rbac_url)

    def test_rbac_service_name(self):
        options = self.parser.parse_args(["--rbac-service-name", "mymaas"])
        self.assertEqual(options.rbac_service_name, "mymaas")
Example #11
0
class TestCmdInit(MAASTestCase):
    def setUp(self):
        super().setUp()
        self.parser = ArgumentParser()
        self.cmd = cli.cmd_init(self.parser)
        self.maas_region_path = init.get_maas_region_bin_path()
        self.call_mock = self.patch(init.subprocess, 'call')
        self.check_output_mock = self.patch(init.subprocess, 'check_output')
        self.check_output_mock.return_value = json.dumps(
            {'external_auth_url': ''})
        # avoid printouts
        self.patch(sys, "stdout", StringIO())

    def test_defaults(self):
        options = self.parser.parse_args([])
        self.assertFalse(options.skip_admin)
        self.assertIsNone(options.admin_username)
        self.assertIsNone(options.admin_password)
        self.assertIsNone(options.admin_email)
        self.assertIsNone(options.admin_ssh_import)
        self.assertFalse(options.enable_idm)
        self.assertIsNone(options.idm_url)
        self.assertIsNone(options.idm_user)
        self.assertIsNone(options.idm_key)
        self.assertIsNone(options.idm_agent_file)

    def test_init_maas_no_idm(self):
        options = self.parser.parse_args([])
        self.cmd(options)
        [createadmin_call] = self.call_mock.mock_calls
        _, args, kwargs = createadmin_call
        self.assertEqual(([self.maas_region_path, 'createadmin'], ), args)
        self.assertEqual({}, kwargs)

    def test_init_maas_with_idm(self):
        options = self.parser.parse_args(['--enable-idm'])
        self.cmd(options)
        configauth_call, createadmin_call = self.call_mock.mock_calls
        _, args1, kwargs1 = configauth_call
        _, args2, kwargs2 = createadmin_call
        self.assertEqual(([self.maas_region_path, 'configauth'], ), args1)
        self.assertEqual({}, kwargs1)
        self.assertEqual(([self.maas_region_path, 'createadmin'], ), args2)
        self.assertEqual({}, kwargs2)
Example #12
0
class TestAddCandidOptions(MAASTestCase):

    def setUp(self):
        super().setUp()
        self.parser = ArgumentParser()
        init.add_candid_options(self.parser)
        self.mock_stderr = self.patch(init.sys, "stderr", StringIO())

    def test_add_candid_options_empty(self):
        options = self.parser.parse_args([])
        self.assertIsNone(options.candid_url)
        self.assertIsNone(options.candid_user)
        self.assertIsNone(options.candid_key)
        self.assertIsNone(options.candid_agent_file)

    def test_add_candid_options_candid_url(self):
        options = self.parser.parse_args(
            ['--idm-url', 'http://candid.example.com/'])
        self.assertEqual(
            'http://candid.example.com/', options.candid_url)

    def test_add_candid_options_candid_domain(self):
        options = self.parser.parse_args(
            ['--candid-domain', 'mydomain'])
        self.assertEqual('mydomain', options.candid_domain)

    def test_add_candid_options_candid_user(self):
        options = self.parser.parse_args(['--idm-user', 'my-user'])
        self.assertEqual('my-user', options.candid_user)

    def test_add_candid_options_candid_key(self):
        options = self.parser.parse_args(['--idm-key', 'my-key'])
        self.assertEqual('my-key', options.candid_key)

    def test_add_candid_options_candid_agent_file(self):
        options = self.parser.parse_args(['--candid-agent-file', 'agent.file'])
        self.assertEqual(options.candid_agent_file, 'agent.file')

    def test_add_candid_options_deprecated_idm_agent_file(self):
        options = self.parser.parse_args(['--idm-agent-file', 'agent.file'])
        self.assertEqual(options.candid_agent_file, 'agent.file')
        self.assertIn(
            'Note: "--idm-agent-file" is deprecated and will be removed, '
            'please use "--candid-agent-file" instead',
            self.mock_stderr.getvalue())

    def test_add_candid_options_candid_admin_group(self):
        options = self.parser.parse_args(
            ['--candid-admin-group', 'admins'])
        self.assertEqual('admins', options.candid_admin_group)
Example #13
0
class TestCreateAdminAccount(MAASTestCase):
    def setUp(self):
        super().setUp()
        self.parser = ArgumentParser()
        init.add_create_admin_options(self.parser)
        self.mock_call = self.patch(init.subprocess, "call")
        self.mock_print_msg = self.patch(init, "print_msg")
        self.maas_region_path = init.get_maas_region_bin_path()

    def test_no_options(self):
        options = self.parser.parse_args([])
        init.create_admin_account(options)
        self.mock_print_msg.assert_called_with("Create first admin account")
        self.mock_call.assert_called_with(
            [self.maas_region_path, "createadmin"])

    def test_username(self):
        options = self.parser.parse_args(["--admin-username", "my-user"])
        init.create_admin_account(options)
        self.mock_print_msg.assert_called_with("Create first admin account")
        self.mock_call.assert_called_with(
            [self.maas_region_path, "createadmin", "--username", "my-user"])

    def test_password(self):
        options = self.parser.parse_args(["--admin-password", "my-pass"])
        init.create_admin_account(options)
        self.mock_print_msg.assert_called_with("Create first admin account")
        self.mock_call.assert_called_with(
            [self.maas_region_path, "createadmin", "--password", "my-pass"])

    def test_email(self):
        options = self.parser.parse_args(["--admin-email", "*****@*****.**"])
        init.create_admin_account(options)
        self.mock_print_msg.assert_called_with("Create first admin account")
        self.mock_call.assert_called_with([
            self.maas_region_path, "createadmin", "--email", "*****@*****.**"
        ])

    def test_ssh_import(self):
        options = self.parser.parse_args(["--admin-ssh-import", "lp:me"])
        init.create_admin_account(options)
        self.mock_print_msg.assert_called_with("Create first admin account")
        self.mock_call.assert_called_with(
            [self.maas_region_path, "createadmin", "--ssh-import", "lp:me"])

    def test_no_print_header(self):
        options = self.parser.parse_args([
            "--admin-username",
            "my-user",
            "--admin-password",
            "my-pass",
            "--admin-email",
            "*****@*****.**",
        ])
        init.create_admin_account(options)
        self.mock_print_msg.assert_not_called()
Example #14
0
class TestCreateAdminAccount(MAASTestCase):

    def setUp(self):
        super().setUp()
        self.parser = ArgumentParser()
        init.add_create_admin_options(self.parser)
        self.mock_call = self.patch(init.subprocess, 'call')
        self.mock_print_msg = self.patch(init, 'print_msg')
        self.maas_region_path = init.get_maas_region_bin_path()

    def test_no_options(self):
        options = self.parser.parse_args([])
        init.create_admin_account(options)
        self.mock_print_msg.assert_called_with('Create first admin account')
        self.mock_call.assert_called_with(
            [self.maas_region_path, 'createadmin'])

    def test_username(self):
        options = self.parser.parse_args(['--admin-username', 'my-user'])
        init.create_admin_account(options)
        self.mock_print_msg.assert_called_with('Create first admin account')
        self.mock_call.assert_called_with(
            [self.maas_region_path, 'createadmin', '--username', 'my-user'])

    def test_password(self):
        options = self.parser.parse_args(['--admin-password', 'my-pass'])
        init.create_admin_account(options)
        self.mock_print_msg.assert_called_with('Create first admin account')
        self.mock_call.assert_called_with(
            [self.maas_region_path, 'createadmin', '--password', 'my-pass'])

    def test_email(self):
        options = self.parser.parse_args(['--admin-email', '*****@*****.**'])
        init.create_admin_account(options)
        self.mock_print_msg.assert_called_with('Create first admin account')
        self.mock_call.assert_called_with(
            [self.maas_region_path,
             'createadmin', '--email', '*****@*****.**'])

    def test_ssh_import(self):
        options = self.parser.parse_args(['--admin-ssh-import', 'lp:me'])
        init.create_admin_account(options)
        self.mock_print_msg.assert_called_with('Create first admin account')
        self.mock_call.assert_called_with(
            [self.maas_region_path, 'createadmin', '--ssh-import', 'lp:me'])

    def test_no_print_header(self):
        options = self.parser.parse_args(
            ['--admin-username', 'my-user', '--admin-password', 'my-pass',
             '--admin-email', '*****@*****.**'])
        init.create_admin_account(options)
        self.mock_print_msg.assert_not_called()
Example #15
0
class TestCmdConfig(MAASTestCase):
    def setUp(self):
        super().setUp()
        self.parser = ArgumentParser()
        self.cmd = snappy.cmd_config(self.parser)
        self.patch(os, "getuid").return_value = 0
        snap_common = self.make_dir()
        snap_data = self.make_dir()
        self.useFixture(EnvironmentVariableFixture("SNAP_COMMON", snap_common))
        self.useFixture(EnvironmentVariableFixture("SNAP_DATA", snap_data))

    def test_show(self):
        # Regression test for LP:1892868
        stdout = io.StringIO()
        self.patch(sys, "stdout", stdout)
        options = self.parser.parse_args([])
        self.assertIsNone(self.cmd(options))
        self.assertEqual(stdout.getvalue(), "Mode: none\n")
Example #16
0
class TestCmdInit(MAASTestCase):
    def setUp(self):
        super().setUp()
        self.parser = ArgumentParser()
        self.cmd = snappy.cmd_init(self.parser)
        self.patch(os, "getuid").return_value = 0
        self.patch(
            os,
            "environ",
            {
                "SNAP": "/snap/maas",
                "SNAP_COMMON": "/snap/maas/common",
                "SNAP_DATA": "/snap/maas/data",
            },
        )
        self.mock_read_input = self.patch(snappy, "read_input")

    def test_init_snap_db_options_prompt(self):
        self.mock_maas_configuration = self.patch(snappy, "MAASConfiguration")
        self.patch(snappy, "set_rpc_secret")
        self.patch(snappy.cmd_init, "_finalize_init")

        self.mock_read_input.side_effect = [
            "http://localhost:5240/MAAS",
            "localhost",
            "db",
            "maas",
            "pwd",
        ]
        options = self.parser.parse_args(["--mode=region+rack"])
        self.cmd(options)
        self.mock_maas_configuration().update.assert_called_once_with({
            "maas_url":
            "http://localhost:5240/MAAS",
            "database_host":
            "localhost",
            "database_name":
            "db",
            "database_user":
            "******",
            "database_pass":
            "******",
        })
Example #17
0
 def test_handlers_registered_using_correct_names(self):
     profile = self.make_profile()
     parser = ArgumentParser()
     api.register_api_commands(parser)
     for resource in profile.values()[0]["description"]["resources"]:
         for action in resource["auth"]["actions"]:
             # Profile names are matched as-is.
             profile_name = profile.keys()[0]
             # Handler names are processed with handler_command_name before
             # being added to the argument parser tree.
             handler_name = handler_command_name(resource["name"])
             # Action names are processed with safe_name before being added
             # to the argument parser tree.
             action_name = safe_name(action["name"])
             # Parsing these names as command-line arguments yields an
             # options object. Its execute attribute is an instance of
             # Action (or a subclass thereof).
             options = parser.parse_args(
                 (profile_name, handler_name, action_name))
             self.assertIsInstance(options.execute, api.Action)
Example #18
0
 def test_handlers_registered_using_correct_names(self):
     profile = self.make_profile()
     parser = ArgumentParser()
     api.register_api_commands(parser)
     for resource in list(profile.values())[0]["description"]["resources"]:
         for action in resource["auth"]["actions"]:
             # Profile names are matched as-is.
             [profile_name] = profile
             # Handler names are processed with handler_command_name before
             # being added to the argument parser tree.
             handler_name = handler_command_name(resource["name"])
             # Action names are processed with safe_name before being added
             # to the argument parser tree.
             action_name = safe_name(action["name"])
             # Parsing these names as command-line arguments yields an
             # options object. Its execute attribute is an instance of
             # Action (or a subclass thereof).
             options = parser.parse_args(
                 (profile_name, handler_name, action_name))
             self.assertIsInstance(options.execute, api.Action)
Example #19
0
class TestCmdInit(MAASTestCase):
    def setUp(self):
        super().setUp()
        self.parser = ArgumentParser()
        self.cmd = snappy.cmd_init(self.parser)
        self.patch(os, 'getuid').return_value = 0
        self.patch(
            os, 'environ', {
                'SNAP': '/snap/maas',
                'SNAP_COMMON': '/snap/maas/common',
                'SNAP_DATA': '/snap/maas/data'
            })
        self.mock_read_input = self.patch(snappy, 'read_input')

    def test_init_snap_db_options_prompt(self):
        self.mock_maas_configuration = self.patch(snappy, 'MAASConfiguration')
        self.patch(snappy, 'set_rpc_secret')
        self.patch(snappy.cmd_init, '_finalize_init')

        self.mock_read_input.side_effect = [
            'http://localhost:5240/MAAS', 'localhost', 'db', 'maas', 'pwd'
        ]
        options = self.parser.parse_args(['--mode=region+rack'])
        self.cmd(options)
        self.mock_maas_configuration().update.assert_called_once_with({
            'maas_url':
            'http://localhost:5240/MAAS',
            'database_host':
            'localhost',
            'database_name':
            'db',
            'database_user':
            '******',
            'database_pass':
            '******'
        })
Example #20
0
class TestCmdInit(MAASTestCase):
    def setUp(self):
        super().setUp()
        self.parser = ArgumentParser()
        self.cmd = cli.cmd_init(self.parser)
        self.maas_region_path = init.get_maas_region_bin_path()
        self.call_mock = self.patch(init.subprocess, 'call')
        self.check_output_mock = self.patch(init.subprocess, 'check_output')
        self.check_output_mock.return_value = json.dumps(
            {'external_auth_url': ''})
        # avoid printouts
        self.mock_stdout = self.patch(init.sys, "stdout", StringIO())
        self.mock_stderr = self.patch(init.sys, "stderr", StringIO())

    def test_defaults(self):
        options = self.parser.parse_args([])
        self.assertFalse(options.skip_admin)
        self.assertIsNone(options.admin_username)
        self.assertIsNone(options.admin_password)
        self.assertIsNone(options.admin_email)
        self.assertIsNone(options.admin_ssh_import)
        self.assertFalse(options.enable_candid)
        self.assertIsNone(options.candid_url)
        self.assertIsNone(options.candid_user)
        self.assertIsNone(options.candid_key)
        self.assertIsNone(options.candid_agent_file)
        self.assertIsNone(options.rbac_url)

    def test_init_maas_no_candid(self):
        options = self.parser.parse_args([])
        self.cmd(options)
        [createadmin_call] = self.call_mock.mock_calls
        _, args, kwargs = createadmin_call
        self.assertEqual(([self.maas_region_path, 'createadmin'], ), args)
        self.assertEqual({}, kwargs)

    def test_init_maas_with_candid(self):
        options = self.parser.parse_args(['--enable-candid'])
        self.cmd(options)
        configauth_call, createadmin_call = self.call_mock.mock_calls
        _, args1, kwargs1 = configauth_call
        _, args2, kwargs2 = createadmin_call
        self.assertEqual(([self.maas_region_path, 'configauth'], ), args1)
        self.assertEqual({}, kwargs1)
        self.assertEqual(([self.maas_region_path, 'createadmin'], ), args2)
        self.assertEqual({}, kwargs2)

    def test_init_maas_with_legacy_idm_option(self):
        options = self.parser.parse_args(['--enable-idm'])
        self.cmd(options)
        configauth_call, createadmin_call = self.call_mock.mock_calls
        _, args1, kwargs1 = configauth_call
        _, args2, kwargs2 = createadmin_call
        self.assertEqual(([self.maas_region_path, 'configauth'], ), args1)
        self.assertEqual({}, kwargs1)
        self.assertEqual(([self.maas_region_path, 'createadmin'], ), args2)
        self.assertEqual({}, kwargs2)
        self.assertIn(
            'Note: "--enable-idm" is deprecated and will be removed, '
            'please use "--enable-candid" instead',
            self.mock_stderr.getvalue())
Example #21
0
class TestCmdInit(MAASTestCase):
    def setUp(self):
        super().setUp()
        self.parser = ArgumentParser()
        self.cmd = snappy.cmd_init(self.parser)
        self.patch(os, "getuid").return_value = 0
        self.snap_common = self.make_dir()
        self.patch(
            os,
            "environ",
            {
                "SNAP": "/snap/maas",
                "SNAP_COMMON": self.snap_common,
                "SNAP_DATA": "/snap/maas/data",
            },
        )
        self.mock_read_input = self.patch(snappy, "read_input")

    def test_init_snap_db_options_prompt(self):
        self.mock_maas_configuration = self.patch(snappy, "MAASConfiguration")
        self.patch(snappy, "set_rpc_secret")
        self.patch(snappy.cmd_init, "_finalize_init")

        self.mock_read_input.side_effect = [
            "postgres://*****:*****@localhost/db",
            "http://*****:*****@dbhost/dbname",
            ]
        )
        settings = snappy.get_database_settings(options)
        self.assertEqual(
            {
                "database_host": "dbhost",
                "database_name": "dbname",
                "database_user": "******",
                "database_pass": "******",
            },
            settings,
        )

    def test_get_database_settings_prompt_dsn(self):
        self.mock_read_input.side_effect = [
            "postgres://*****:*****@dbhost/dbname"
        ]
        options = self.parser.parse_args(["region+rack"])
        settings = snappy.get_database_settings(options)
        self.assertEqual(
            {
                "database_host": "dbhost",
                "database_name": "dbname",
                "database_user": "******",
                "database_pass": "******",
            },
            settings,
        )

    def test_get_database_settings_maas_test_db_prompt_default(self):
        options = self.parser.parse_args(["region+rack"])
        os.mkdir(os.path.join(self.snap_common, "test-db-socket"))
        self.mock_read_input.side_effect = [""]
        settings = snappy.get_database_settings(options)
        self.assertEqual(
            {
                "database_host": f"{self.snap_common}/test-db-socket",
                "database_name": "maasdb",
                "database_user": "******",
                "database_pass": None,
            },
            settings,
        )

    def test_get_database_settings_maas_test_db_prompt_no_default(self):
        options = self.parser.parse_args(["region+rack"])
        self.mock_read_input.side_effect = ["", "postgres:///?user=foo"]
        settings = snappy.get_database_settings(options)
        self.assertEqual(
            {
                "database_host": "localhost",
                "database_name": "foo",
                "database_user": "******",
                "database_pass": None,
            },
            settings,
        )

    def test_get_database_settings_maas_test_db(self):
        options = self.parser.parse_args(
            ["region+rack", "--database-uri", "maas-test-db:///"]
        )
        settings = snappy.get_database_settings(options)
        self.assertEqual(
            {
                "database_host": f"{self.snap_common}/test-db-socket",
                "database_name": "maasdb",
                "database_user": "******",
                "database_pass": None,
            },
            settings,
        )

    def test_get_database_settings_minimal_postgres(self):
        options = self.parser.parse_args(
            ["region+rack", "--database-uri", "postgres:///?user=myuser"]
        )
        settings = snappy.get_database_settings(options)
        self.assertEqual(
            {
                "database_host": "localhost",
                "database_name": "myuser",
                "database_user": "******",
                "database_pass": None,
            },
            settings,
        )

    def test_get_database_settings_full_postgres(self):
        options = self.parser.parse_args(
            [
                "region+rack",
                "--database-uri",
                "postgres://*****:*****@myhost:1234/mydb",
            ]
        )
        settings = snappy.get_database_settings(options)
        self.assertEqual(
            {
                "database_host": "myhost",
                "database_name": "mydb",
                "database_user": "******",
                "database_pass": "******",
                "database_port": 1234,
            },
            settings,
        )

    def test_get_database_settings_invalid_parameters(self):
        options = self.parser.parse_args(
            [
                "region+rack",
                "--database-uri",
                "postgres://*****:*****@myhost:1234/mydb?foo=bar",
            ]
        )
        error = self.assertRaises(
            snappy.DatabaseSettingsError, snappy.get_database_settings, options
        )
        self.assertEqual(
            "Error parsing database URI: "
            'invalid dsn: invalid URI query parameter: "foo"',
            str(error),
        )

    def test_get_database_settings_unsupported_parameters(self):
        options = self.parser.parse_args(
            [
                "region+rack",
                "--database-uri",
                "postgres://*****:*****@myhost/?passfile=foo&options=bar",
            ]
        )
        error = self.assertRaises(
            snappy.DatabaseSettingsError, snappy.get_database_settings, options
        )
        self.assertEqual(
            "Error parsing database URI: "
            "Unsupported parameters: options, passfile",
            str(error),
        )

    def test_get_database_settings_missing_user(self):
        options = self.parser.parse_args(
            ["region+rack", "--database-uri", "postgres://myhost/"]
        )
        error = self.assertRaises(
            snappy.DatabaseSettingsError, snappy.get_database_settings, options
        )
        self.assertEqual(
            "No user found in URI: postgres://myhost/", str(error)
        )

    def test_get_database_settings_invalid_maas_test_db(self):
        options = self.parser.parse_args(
            ["region+rack", "--database-uri", "maas-test-db:///foo"]
        )
        error = self.assertRaises(
            snappy.DatabaseSettingsError, snappy.get_database_settings, options
        )
        self.assertEqual(
            "Database URI needs to be either 'maas-test-db:///' or start with "
            "'postgres://'",
            str(error),
        )

    def test_get_database_settings_incomplete_postgres_uri(self):
        # The URI needs to start with at least postgres:// before we
        # even try to parse it.
        options = self.parser.parse_args(
            ["region+rack", "--database-uri", "postgres:/"]
        )
        error = self.assertRaises(
            snappy.DatabaseSettingsError, snappy.get_database_settings, options
        )
        self.assertEqual(
            "Database URI needs to be either 'maas-test-db:///' or start with "
            "'postgres://'",
            str(error),
        )
Example #22
0
class TestConfigureAuthentication(MAASTestCase):
    def setUp(self):
        super().setUp()
        self.maas_bin_path = 'snap-path/bin/maas-region'
        self.mock_subprocess = self.patch(init, 'subprocess')
        self.mock_environ = patch.dict(init.os.environ, {'SNAP': 'snap-path'},
                                       clear=True)
        self.mock_environ.start()
        self.parser = ArgumentParser()
        init.add_rbac_options(self.parser)
        init.add_candid_options(self.parser)

    def tearDown(self):
        self.mock_subprocess.stop()
        self.mock_environ.stop()
        super().tearDown()

    def test_no_options(self):
        options = self.parser.parse_args([])
        init.configure_authentication(options)
        [config_call] = self.mock_subprocess.mock_calls
        method, args, kwargs = config_call
        self.assertEqual('call', method)
        self.assertEqual(([self.maas_bin_path, 'configauth'], ), args)
        self.assertEqual({}, kwargs)

    def test_rbac_url(self):
        config_auth_args = ['--rbac-url', 'http://rrbac.example.com/']
        options = self.parser.parse_args(config_auth_args)
        init.configure_authentication(options)
        [config_call] = self.mock_subprocess.mock_calls
        method, args, kwargs = config_call
        self.assertEqual('call', method)
        self.assertEqual(
            ([self.maas_bin_path, 'configauth'] + config_auth_args, ), args)
        self.assertEqual({}, kwargs)

    def test_idm_url(self):
        config_auth_args = ['--idm-url', 'http://candid.example.com/']
        options = self.parser.parse_args(config_auth_args)
        init.configure_authentication(options)
        [config_call] = self.mock_subprocess.mock_calls
        method, args, kwargs = config_call
        self.assertEqual('call', method)
        self.assertEqual(
            ([self.maas_bin_path, 'configauth'] + config_auth_args, ), args)
        self.assertEqual({}, kwargs)

    def test_idm_user(self):
        config_auth_args = ['--idm-user', 'some-user']
        options = self.parser.parse_args(config_auth_args)
        init.configure_authentication(options)
        [config_call] = self.mock_subprocess.mock_calls
        method, args, kwargs = config_call
        self.assertEqual('call', method)
        self.assertEqual(
            ([self.maas_bin_path, 'configauth'] + config_auth_args, ), args)
        self.assertEqual({}, kwargs)

    def test_idm_key(self):
        config_auth_args = ['--idm-key', 'some-key']
        options = self.parser.parse_args(config_auth_args)
        init.configure_authentication(options)
        [config_call] = self.mock_subprocess.mock_calls
        method, args, kwargs = config_call
        self.assertEqual('call', method)
        self.assertEqual(
            ([self.maas_bin_path, 'configauth'] + config_auth_args, ), args)
        self.assertEqual({}, kwargs)

    def test_candid_agent_file(self):
        _, agent_file_path = tempfile.mkstemp()
        self.addCleanup(os.remove, agent_file_path)
        config_auth_args = ['--candid-agent-file', agent_file_path]
        options = self.parser.parse_args(config_auth_args)
        init.configure_authentication(options)
        [config_call] = self.mock_subprocess.mock_calls
        method, args, kwargs = config_call
        self.assertEqual('call', method)
        self.assertEqual(
            ([self.maas_bin_path, 'configauth'] + config_auth_args, ), args)
        self.assertEqual({}, kwargs)

    def test_full(self):
        _, agent_file = tempfile.mkstemp()
        self.addCleanup(os.remove, agent_file)
        config_auth_args = [
            '--idm-url', 'http://candid.example.com/', '--idm-user',
            'candid-user', '--idm-key', 'candid-key', '--candid-agent-file',
            agent_file
        ]
        options = self.parser.parse_args(config_auth_args)
        init.configure_authentication(options)
        [config_call] = self.mock_subprocess.mock_calls
        method, args, kwargs = config_call
        self.assertEqual('call', method)
        self.assertEqual(
            ([self.maas_bin_path, 'configauth'] + config_auth_args, ), args)
        self.assertEqual({}, kwargs)