コード例 #1
0
 def register(self, client):
     super(KeystoneToken, self).register(client)
     self._persist_filename = os.path.join(self.registry.config.data_path,
                                           "keystone.bpickle")
     self._persist = Persist(filename=self._persist_filename)
     self.registry.reactor.call_every(self.registry.config.flush_interval,
                                      self.flush)
コード例 #2
0
    def run_script(self,
                   shell,
                   code,
                   user=None,
                   time_limit=None,
                   attachments=None,
                   server_supplied_env=None):
        """
        Run a script based on a shell and the code.

        A file will be written with #!<shell> as the first line, as executable,
        and run as the given user.

        XXX: Handle the 'reboot' and 'killall landscape-client' commands
        gracefully.

        @param shell: The interpreter to use.
        @param code: The code to run.
        @param user: The username to run the process as.
        @param time_limit: The number of seconds to allow the process to run
            before killing it and failing the returned Deferred with a
            L{ProcessTimeLimitReachedError}.
        @param attachments: C{dict} of filename/data attached to the script.

        @return: A deferred that will fire with the data printed by the process
            or fail with a L{ProcessTimeLimitReachedError}.
        """
        if not os.path.exists(shell.split()[0]):
            return fail(UnknownInterpreterError(shell))

        uid, gid, path = get_user_info(user)

        fd, filename = tempfile.mkstemp()
        script_file = os.fdopen(fd, "w")
        self.write_script_file(script_file, filename, shell, code, uid, gid)

        env = {"PATH": UBUNTU_PATH, "USER": user or "", "HOME": path or ""}
        if server_supplied_env:
            env.update(server_supplied_env)
        old_umask = os.umask(0022)

        if attachments:
            persist = Persist(filename=os.path.join(
                self.registry.config.data_path, "broker.bpickle"))
            persist = persist.root_at("registration")
            computer_id = persist.get("secure-id")
            d = self._save_attachments(attachments, uid, gid, computer_id)
        else:
            d = succeed(None)

        def prepare_script(attachment_dir):

            if attachment_dir is not None:
                env["LANDSCAPE_ATTACHMENTS"] = attachment_dir

            return self._run_script(filename, uid, gid, path, env, time_limit)

        d.addCallback(prepare_script)
        return d.addBoth(self._cleanup, filename, env, old_umask)
コード例 #3
0
class KeystoneToken(DataWatcher):
    """
    A plugin which pulls the admin_token from the keystone configuration file
    and sends it to the landscape server.
    """
    message_type = "keystone-token"
    message_key = "data"
    run_interval = 60 * 15
    scope = "openstack"

    def __init__(self, keystone_config_file=KEYSTONE_CONFIG_FILE):
        self._keystone_config_file = keystone_config_file

    def register(self, client):
        super(KeystoneToken, self).register(client)
        self._persist_filename = os.path.join(self.registry.config.data_path,
                                              "keystone.bpickle")
        self._persist = Persist(filename=self._persist_filename)
        self.registry.reactor.call_every(self.registry.config.flush_interval,
                                         self.flush)

    def _reset(self):
        """
        Reset the persist.
        """
        self._persist.remove("data")

    def flush(self):
        self._persist.save(self._persist_filename)

    def get_data(self):
        """
        Return the Keystone administrative token.
        """
        if not os.path.exists(self._keystone_config_file):
            return None

        config = ConfigParser()
        if _PY3:
            # We need to use the surrogateescape error handler as the
            # admin_token my contain arbitrary bytes. The ConfigParser in
            # Python 2 on the other hand does not support read_string.
            config_str = read_binary_file(
                self._keystone_config_file).decode("utf-8", "surrogateescape")
            config.read_string(config_str)
        else:
            config.read(self._keystone_config_file)
        try:
            admin_token = config.get("DEFAULT", "admin_token")
        except NoOptionError:
            logging.error("KeystoneToken: No admin_token found in %s"
                          % (self._keystone_config_file))
            return None
        # There is no support for surrogateescape in Python 2, but we actually
        # have bytes in this case anyway.
        if _PY3:
            admin_token = admin_token.encode("utf-8", "surrogateescape")

        return admin_token
コード例 #4
0
 def test_that_resynchronize_clears_message_blackhole(self):
     """
     When a resynchronisation event occurs the block on new messages
     being stored is lifted.
     """
     self.reactor.fire("resynchronize-clients", [])
     persist = Persist(filename=self.persist_filename)
     self.assertFalse(persist.get("blackhole-messages"))
コード例 #5
0
    def test_flush_saves_persist(self):
        """
        The L{Monitor.flush} method saves any changes made to the persist
        database.
        """
        self.monitor.persist.set("a", 1)
        self.monitor.flush()

        persist = Persist()
        persist.load(self.monitor.persist_filename)
        self.assertEqual(persist.get("a"), 1)
コード例 #6
0
    def test_accumulate_skipped_step(self):
        """
        step:    0              5              10             15
               --|--+--+--+--+--|--+--+--+--+--|--+--+--+--+--|--
        value:   0                                   4
        """
        persist = Persist()
        accumulate = Accumulator(persist, 5)

        self.assertEqual(persist.get("key"), None)
        step_data = accumulate(12, 4, "key")
        self.assertEqual(step_data, None)
        self.assertEqual(persist.get("key"), (12, 8))
コード例 #7
0
    def test_accumulate(self):
        """
        step:    0              5
               --|--+--+--+--+--|--
        value:   0              4
        """
        persist = Persist()
        accumulate = Accumulator(persist, 5)

        self.assertEqual(persist.get("key"), None)
        step_data = accumulate(5, 4, "key")
        self.assertEqual(step_data, (5, 4))
        self.assertEqual(persist.get("key"), (5, 0))
コード例 #8
0
    def test_flush_after_exchange(self):
        """
        The L{Monitor.exchange} method flushes the monitor after
        C{exchange} on all plugins has been called.
        """
        plugin = BrokerClientPlugin()
        plugin.exchange = lambda: self.monitor.persist.set("a", 1)
        self.monitor.add(plugin)
        self.monitor.exchange()

        persist = Persist()
        persist.load(self.monitor.persist_filename)
        self.assertEqual(persist.get("a"), 1)
コード例 #9
0
    def test_accumulate_with_first_value_on_step_boundary(self):
        """
        step:    0              5
               --|--+--+--+--+--|--
        value:   14
        """
        persist = Persist()
        accumulate = Accumulator(persist, 5)

        self.assertEqual(persist.get("key"), None)
        step_data = accumulate(0, 14, "key")
        self.assertEqual(step_data, None)
        self.assertEqual(persist.get("key"), (0, 0))
コード例 #10
0
def get_versioned_persist(service):
    """Get a L{Persist} database with upgrade rules applied.

    Load a L{Persist} database for the given C{service} and upgrade or
    mark as current, as necessary.
    """
    persist = Persist(filename=service.persist_filename)
    upgrade_manager = UPGRADE_MANAGERS[service.service_name]
    if os.path.exists(service.persist_filename):
        upgrade_manager.apply(persist)
    else:
        upgrade_manager.initialize(persist)
    persist.save(service.persist_filename)
    return persist
コード例 #11
0
    def test_commit(self):
        """
        The Message Store can be told to save its persistent data to disk on
        demand.
        """
        filename = self.makeFile()
        store = MessageStore(Persist(filename=filename), self.temp_dir)
        store.set_accepted_types(["foo", "bar"])

        self.assertFalse(os.path.exists(filename))
        store.commit()
        self.assertTrue(os.path.exists(filename))

        store = MessageStore(Persist(filename=filename), self.temp_dir)
        self.assertEqual(set(store.get_accepted_types()), set(["foo", "bar"]))
コード例 #12
0
    def test_accumulate_non_zero_accumulated_value(self):
        """
        step:    5              10             15
               --|--+--+--+--+--|--+--+--+--+--|--
        value:         4                 3
        """
        persist = Persist()
        accumulate = Accumulator(persist, 5)

        # Persist data that would have been stored when
        # accumulate(7, 4, "key") was called.
        persist.set("key", (7, 8))
        step_data = accumulate(13, 3, "key")
        self.assertEqual(step_data, (10, float((2 * 4) + (3 * 3)) / 5))
        self.assertEqual(persist.get("key"), (13, 9))
コード例 #13
0
    def test_accumulate_within_step_with_nonzero_start_accumulated_value(self):
        """
        step:    0              5
               --|--+--+--+--+--|--
        value:   0     3     4
        """
        persist = Persist()
        accumulate = Accumulator(persist, 5)

        # Persist data that would have been stored when
        # accumulate(2, 3, "key") was called.
        persist.set("key", (2, 6))
        step_data = accumulate(4, 4, "key")
        self.assertEqual(step_data, None)
        self.assertEqual(persist.get("key"), (4, 14))
コード例 #14
0
 def handler(message):
     Persist(filename=self.persist_filename)
     store = MessageStore(self.persist, self.config.message_store_path)
     self.assertEqual(store.get_server_sequence(),
                      self.message_counter)
     self.message_counter += 1
     handled.append(True)
コード例 #15
0
def is_registered(config):
    """Return whether the client is already registered."""
    persist_filename = os.path.join(
        config.data_path, "{}.bpickle".format(BrokerService.service_name))
    persist = Persist(filename=persist_filename)
    identity = Identity(config, persist)
    return bool(identity.secure_id)
コード例 #16
0
class KeystoneToken(DataWatcher):
    """
    A plugin which pulls the admin_token from the keystone configuration file
    and sends it to the landscape server.
    """
    message_type = "keystone-token"
    message_key = "data"
    run_interval = 60 * 15
    scope = "openstack"

    def __init__(self, keystone_config_file=KEYSTONE_CONFIG_FILE):
        self._keystone_config_file = keystone_config_file

    def register(self, client):
        super(KeystoneToken, self).register(client)
        self._persist_filename = os.path.join(self.registry.config.data_path,
                                              "keystone.bpickle")
        self._persist = Persist(filename=self._persist_filename)
        self.registry.reactor.call_every(self.registry.config.flush_interval,
                                         self.flush)

    def _reset(self):
        """
        Reset the persist.
        """
        self._persist.remove("data")

    def flush(self):
        self._persist.save(self._persist_filename)

    def get_data(self):
        """
        Return the Keystone administrative token.
        """
        if not os.path.exists(self._keystone_config_file):
            return None

        config = ConfigParser()
        config.read(self._keystone_config_file)
        try:
            admin_token = config.get("DEFAULT", "admin_token")
        except NoOptionError:
            logging.error("KeystoneToken: No admin_token found in %s" %
                          (self._keystone_config_file))
            return None
        return admin_token
コード例 #17
0
    def setUp(self):
        super(UserChangesTest, self).setUp()
        self.persist = Persist()
        self.shadow_file = self.makeFile("""\
jdoe:$1$xFlQvTqe$cBtrNEDOIKMy/BuJoUdeG0:13348:0:99999:7:::
psmith:!:13348:0:99999:7:::
sbarnes:$1$q7sz09uw$q.A3526M/SHu8vUb.Jo1A/:13349:0:99999:7:::
""")
コード例 #18
0
class IdentityTest(LandscapeTest):

    helpers = [BrokerConfigurationHelper]

    def setUp(self):
        super(IdentityTest, self).setUp()
        self.persist = Persist(filename=self.makePersistFile())
        self.identity = Identity(self.config, self.persist)

    def check_persist_property(self, attr, persist_name):
        value = "VALUE"
        self.assertEqual(getattr(self.identity, attr), None,
                         "%r attribute should default to None, not %r" %
                         (attr, getattr(self.identity, attr)))
        setattr(self.identity, attr, value)
        self.assertEqual(getattr(self.identity, attr), value,
                         "%r attribute should be %r, not %r" %
                         (attr, value, getattr(self.identity, attr)))
        self.assertEqual(
            self.persist.get(persist_name), value,
            "%r not set to %r in persist" % (persist_name, value))

    def check_config_property(self, attr):
        value = "VALUE"
        setattr(self.config, attr, value)
        self.assertEqual(getattr(self.identity, attr), value,
                         "%r attribute should be %r, not %r" %
                         (attr, value, getattr(self.identity, attr)))

    def test_secure_id(self):
        self.check_persist_property("secure_id",
                                    "registration.secure-id")

    def test_secure_id_as_unicode(self):
        """secure-id is expected to be retrieved as unicode."""
        self.identity.secure_id = b"spam"
        self.assertEqual(self.identity.secure_id, "spam")

    def test_insecure_id(self):
        self.check_persist_property("insecure_id",
                                    "registration.insecure-id")

    def test_computer_title(self):
        self.check_config_property("computer_title")

    def test_account_name(self):
        self.check_config_property("account_name")

    def test_registration_key(self):
        self.check_config_property("registration_key")

    def test_client_tags(self):
        self.check_config_property("tags")

    def test_access_group(self):
        self.check_config_property("access_group")
コード例 #19
0
 def create_store(self):
     persist = Persist(filename=self.persist_filename)
     store = MessageStore(persist, self.temp_dir, 20)
     store.set_accepted_types(["empty", "data", "resynchronize"])
     store.add_schema(Message("empty", {}))
     store.add_schema(Message("empty2", {}))
     store.add_schema(Message("data", {"data": Bytes()}))
     store.add_schema(Message("unaccepted", {"data": Bytes()}))
     store.add_schema(Message("resynchronize", {}))
     return store
コード例 #20
0
ファイル: helpers.py プロジェクト: panlinux/landscape-client
 def set_up(self, test_case):
     super(MonitorHelper, self).set_up(test_case)
     persist = Persist()
     persist_filename = test_case.makePersistFile()
     test_case.config = MonitorConfiguration()
     test_case.config.load(["-c", test_case.config_filename])
     test_case.reactor = FakeReactor()
     test_case.monitor = Monitor(test_case.reactor, test_case.config,
                                 persist, persist_filename)
     test_case.monitor.broker = test_case.remote
     test_case.mstore = test_case.broker_service.message_store
コード例 #21
0
    def test_run_with_attachment_ids(self):
        """
        The most recent protocol for script message doesn't include the
        attachment body inside the message itself, but instead gives an
        attachment ID, and the plugin fetches the files separately.
        """
        self.manager.config.url = "https://localhost/message-system"
        persist = Persist(
            filename=os.path.join(self.config.data_path, "broker.bpickle"))
        registration_persist = persist.root_at("registration")
        registration_persist.set("secure-id", "secure_id")
        persist.save()

        patch_fetch = mock.patch(
            "landscape.client.manager.scriptexecution.fetch_async")
        mock_fetch = patch_fetch.start()
        mock_fetch.return_value = succeed(b"some other data")

        headers = {
            "User-Agent": "landscape-client/%s" % VERSION,
            "Content-Type": "application/octet-stream",
            "X-Computer-ID": "secure_id"
        }

        result = self.plugin.run_script(
            u"/bin/sh",
            u"ls $LANDSCAPE_ATTACHMENTS && cat $LANDSCAPE_ATTACHMENTS/file1",
            attachments={u"file1": 14})

        def check(result):
            self.assertEqual(result, "file1\nsome other data")
            mock_fetch.assert_called_with("https://localhost/attachment/14",
                                          headers=headers,
                                          cainfo=None)

        def cleanup(result):
            patch_fetch.stop()
            # We have to return the Failure or result to get a working test.
            return result

        return result.addCallback(check).addBoth(cleanup)
コード例 #22
0
    def test_run_with_attachment_ids_and_ssl(self):
        """
        When fetching attachments, L{ScriptExecution} passes the optional ssl
        certificate file if the configuration specifies it.
        """
        self.manager.config.url = "https://localhost/message-system"
        self.manager.config.ssl_public_key = "/some/key"
        persist = Persist(
            filename=os.path.join(self.config.data_path, "broker.bpickle"))
        registration_persist = persist.root_at("registration")
        registration_persist.set("secure-id", "secure_id")
        persist.save()

        patch_fetch = mock.patch(
            "landscape.client.manager.scriptexecution.fetch_async")
        mock_fetch = patch_fetch.start()
        mock_fetch.return_value = succeed(b"some other data")

        headers = {
            "User-Agent": "landscape-client/%s" % VERSION,
            "Content-Type": "application/octet-stream",
            "X-Computer-ID": "secure_id"
        }

        result = self.plugin.run_script(
            u"/bin/sh",
            u"ls $LANDSCAPE_ATTACHMENTS && cat $LANDSCAPE_ATTACHMENTS/file1",
            attachments={u"file1": 14})

        def check(result):
            self.assertEqual(result, "file1\nsome other data")
            mock_fetch.assert_called_with("https://localhost/attachment/14",
                                          headers=headers,
                                          cainfo="/some/key")

        def cleanup(result):
            patch_fetch.stop()
            return result

        return result.addCallback(check).addBoth(cleanup)
コード例 #23
0
    def test_fetch_attachment_failure(self, mock_fetch):
        """
        If the plugin fails to retrieve the attachments with a
        L{HTTPCodeError}, a specific error code is shown.
        """
        self.manager.config.url = "https://localhost/message-system"
        persist = Persist(
            filename=os.path.join(self.config.data_path, "broker.bpickle"))
        registration_persist = persist.root_at("registration")
        registration_persist.set("secure-id", "secure_id")
        persist.save()
        headers = {
            "User-Agent": "landscape-client/%s" % VERSION,
            "Content-Type": "application/octet-stream",
            "X-Computer-ID": "secure_id"
        }

        mock_fetch.return_value = fail(HTTPCodeError(404, "Not found"))

        self.manager.add(ScriptExecutionPlugin())
        result = self._send_script("/bin/sh",
                                   "echo hi",
                                   attachments={u"file1": 14})

        def got_result(ignored):
            self.assertMessages(
                self.broker_service.message_store.get_pending_messages(),
                [{
                    "type": "operation-result",
                    "operation-id": 123,
                    "result-text": "Server returned HTTP code 404",
                    "result-code": FETCH_ATTACHMENTS_FAILED_RESULT,
                    "status": FAILED
                }])
            mock_fetch.assert_called_with("https://localhost/attachment/14",
                                          headers=headers,
                                          cainfo=None)

        return result.addCallback(got_result)
コード例 #24
0
 def test_reset_exchange_token_on_failure(self):
     """
     If an exchange fails we set the value of the next exchange token to
     C{None}, so we can authenticate ourselves even if we couldn't receive
     a valid token.
     """
     self.mstore.set_exchange_token("abcd-efgh")
     self.mstore.commit()
     self.transport.exchange = lambda *args, **kwargs: None
     self.exchanger.exchange()
     # Check that the change was persisted
     persist = Persist(filename=self.persist_filename)
     store = MessageStore(persist, self.config.message_store_path)
     self.assertIs(None, store.get_exchange_token())
コード例 #25
0
 def set_up(self, test_case):
     super(ExchangeHelper, self).set_up(test_case)
     test_case.persist_filename = test_case.makePersistFile()
     test_case.persist = Persist(filename=test_case.persist_filename)
     test_case.mstore = get_default_message_store(
         test_case.persist, test_case.config.message_store_path)
     test_case.identity = Identity(test_case.config, test_case.persist)
     test_case.transport = FakeTransport(None, test_case.config.url,
                                         test_case.config.ssl_public_key)
     test_case.reactor = FakeReactor()
     test_case.exchange_store = ExchangeStore(
         test_case.config.exchange_store_path)
     test_case.exchanger = MessageExchange(
         test_case.reactor, test_case.mstore, test_case.transport,
         test_case.identity, test_case.exchange_store, test_case.config)
コード例 #26
0
    def test_creating_loads_persist(self):
        """
        If C{persist_filename} exists, it is loaded by the constructor.
        """
        filename = self.makeFile()

        persist = Persist()
        persist.set("a", "Hi there!")
        persist.save(filename)

        monitor = Monitor(self.reactor,
                          self.config,
                          persist=Persist(),
                          persist_filename=filename)
        self.assertEqual(monitor.persist.get("a"), "Hi there!")
コード例 #27
0
 def setUp(self):
     super(IdentityTest, self).setUp()
     self.persist = Persist(filename=self.makePersistFile())
     self.identity = Identity(self.config, self.persist)
コード例 #28
0
 def build_persist(self, *args, **kwargs):
     return Persist(*args, **kwargs)
コード例 #29
0
 def build_persist(self, *args, **kwargs):
     return RootedPersist(Persist(), "root.path", *args, **kwargs)
コード例 #30
0
 def build_persist(self, *args, **kwargs):
     return Persist(PickleBackend(), *args, **kwargs)