async def test():
            get_rpc_mock.return_value = self.channel

            # Ensure setup is initialized properly
            self.nid_client.clear()
            self.idlist_client.clear()
            self.log_client.clear()
            self.foo_client.clear()

            key = 'id1'
            foo = Foo("boo", 4)
            self.nid_client[key] = NetworkID(id='foo')
            self.idlist_client[key] = IDList(ids=['bar', 'blah'])
            self.foo_client[key] = foo
            # Increment version
            self.idlist_client[key] = IDList(ids=['bar', 'blah'])

            req = await self.state_replicator._collect_states_to_replicate()
            self.assertEqual(3, len(req.states))

            # Ensure in-memory map updates properly
            await self.state_replicator._send_to_state_service(req)
            self.assertEqual(3, len(self.state_replicator._state_versions))
            mem_key1 = make_mem_key('id1', NID_TYPE)
            mem_key2 = make_mem_key('aaa-bbb:id1',
                                    IDList_TYPE)
            mem_key3 = make_mem_key('id1', FOO_TYPE)
            self.assertEqual(1,
                             self.state_replicator._state_versions[mem_key1])
            self.assertEqual(2,
                             self.state_replicator._state_versions[mem_key2])
            self.assertEqual(1,
                             self.state_replicator._state_versions[mem_key3])

            # Now add new state and update some existing state
            key2 = 'id2'
            self.nid_client[key2] = NetworkID(id='bar')
            self.idlist_client[key] = IDList(ids=['bar', 'foo'])
            req = await self.state_replicator._collect_states_to_replicate()
            self.assertEqual(2, len(req.states))

            # Ensure in-memory map updates properly
            await self.state_replicator._send_to_state_service(req)
            self.assertEqual(4, len(self.state_replicator._state_versions))
            mem_key4 = make_mem_key('id2', NID_TYPE)
            self.assertEqual(1,
                             self.state_replicator._state_versions[mem_key1])
            self.assertEqual(3,
                             self.state_replicator._state_versions[mem_key2])
            self.assertEqual(1,
                             self.state_replicator._state_versions[mem_key3])
            self.assertEqual(1,
                             self.state_replicator._state_versions[mem_key4])
Example #2
0
        async def test():
            get_grpc_mock.return_value = self.channel
            self.nid_client.clear()
            self.idlist_client.clear()
            self.log_client.clear()
            self.foo_client.clear()

            key = 'id1'
            self.nid_client[key] = NetworkID(id='foo')
            req = await self.state_replicator._collect_states_to_replicate()
            self.assertEqual(1, len(req.states))

            # Ensure in-memory map updates properly
            await self.state_replicator._send_to_state_service(req)
            self.assertEqual(1, len(self.state_replicator._state_versions))
            mem_key1 = make_mem_key('id1', NID_TYPE)
            self.assertEqual(1,
                             self.state_replicator._state_versions[mem_key1])

            # Now delete state and ensure in-memory map gets updated properly
            del self.nid_client[key]
            req = await self.state_replicator._collect_states_to_replicate()
            self.assertIsNone(req)

            await self.state_replicator._cleanup_deleted_keys()
            self.assertFalse(key in self.state_replicator._state_versions)
Example #3
0
    async def _resync(self):
        states_to_sync = []
        for redis_dict in self._redis_dicts:
            for key in redis_dict:
                version = redis_dict.get_version(key)
                device_id = make_scoped_device_id(key, redis_dict.state_scope)
                state_id = StateID(type=redis_dict.redis_type,
                                   deviceID=device_id)
                id_and_version = IDAndVersion(id=state_id, version=version)
                states_to_sync.append(id_and_version)

        if len(states_to_sync) == 0:
            logging.debug("Not re-syncing state. No local state found.")
            return
        state_client = self._grpc_client_manager.get_client()
        request = SyncStatesRequest(states=states_to_sync)
        response = await grpc_async_wrapper(
            state_client.SyncStates.future(
                request,
                DEFAULT_GRPC_TIMEOUT,
            ), self._loop)
        unsynced_states = set()
        for id_and_version in response.unsyncedStates:
            unsynced_states.add(
                (id_and_version.id.type, id_and_version.id.deviceID))
        # Update in-memory map to add already synced states
        for state in request.states:
            in_mem_key = make_mem_key(state.id.deviceID, state.id.type)
            if (state.id.type, state.id.deviceID) not in unsynced_states:
                self._state_versions[in_mem_key] = state.version

        self._has_resync_completed = True
        logging.info("Successfully resynced state with Orchestrator!")
Example #4
0
    async def _send_to_state_service(self, request: ReportStatesRequest):
        state_client = self._grpc_client_manager.get_client()
        try:
            response = await grpc_async_wrapper(
                state_client.ReportStates.future(
                    request,
                    DEFAULT_GRPC_TIMEOUT,
                ), self._loop)

        except grpc.RpcError as err:
            logging.error("GRPC call failed for state replication: %s", err)
        else:
            unreplicated_states = set()
            for idAndError in response.unreportedStates:
                logging.warning("Failed to replicate state for (%s,%s): %s",
                                idAndError.type, idAndError.deviceID,
                                idAndError.error)
                unreplicated_states.add((idAndError.type, idAndError.deviceID))
            # Update in-memory map for successfully reported states
            for state in request.states:
                if (state.type, state.deviceID) in unreplicated_states:
                    continue
                in_mem_key = make_mem_key(state.deviceID, state.type)
                self._state_versions[in_mem_key] = state.version

                logging.debug(
                    "Successfully replicated state for: "
                    "deviceID: %s,"
                    "type: %s, "
                    "version: %d", state.deviceID, state.type, state.version)
        finally:
            # reset timeout to config-specified + some buffer
            self.set_timeout(self._interval * 2)
Example #5
0
    async def _collect_states_to_replicate(self):
        states_to_report = []
        for redis_dict in self._redis_dicts:
            for key in redis_dict:
                device_id = make_scoped_device_id(key, redis_dict.state_scope)
                in_mem_key = make_mem_key(device_id, redis_dict.redis_type)
                redis_version = redis_dict.get_version(key)
                self._state_keys_from_current_iteration.add(in_mem_key)
                if in_mem_key in self._state_versions and \
                        self._state_versions[in_mem_key] == redis_version:
                    continue

                redis_state = redis_dict.get(key)
                if redis_dict.state_format == PROTO_FORMAT:
                    state_to_serialize = MessageToDict(redis_state)
                    serialized_json_state = json.dumps(state_to_serialize)
                else:
                    serialized_json_state = jsonpickle.encode(redis_state)
                state_proto = State(type=redis_dict.redis_type,
                      deviceID=device_id,
                      value=serialized_json_state.encode("utf-8"),
                      version=redis_version)

                states_to_report.append(state_proto)

        if len(states_to_report) == 0:
            logging.debug("Not replicating state. No state has changed!")
            return None
        return ReportStatesRequest(states=states_to_report)
    async def _collect_states_to_replicate(self):
        states_to_report = []
        for redis_dict in self._redis_dicts:
            for key in redis_dict:
                redis_state = redis_dict.get(key)
                device_id = make_scoped_device_id(key, redis_dict.state_scope)

                in_mem_key = make_mem_key(device_id, redis_dict.redis_type)
                if redis_state is None:
                    logging.debug(
                        "Content of key %s is empty, skipping",
                        in_mem_key,
                    )
                    continue

                redis_version = redis_dict.get_version(key)
                self._state_keys_from_current_iteration.add(in_mem_key)
                if in_mem_key in self._state_versions and \
                        self._state_versions[in_mem_key] == redis_version:
                    logging.debug(
                        "key %s already read on this iteration, skipping",
                        in_mem_key,
                    )
                    continue

                try:
                    if redis_dict.state_format == PROTO_FORMAT:
                        state_to_serialize = MessageToDict(redis_state)
                        serialized_json_state = json.dumps(state_to_serialize)
                    else:
                        serialized_json_state = jsonpickle.encode(redis_state)
                except Exception as e:  # pylint: disable=broad-except
                    logging.error(
                        "Found bad state for %s for %s, not "
                        "replicating this state: %s",
                        key,
                        device_id,
                        e,
                    )
                    continue

                state_proto = State(
                    type=redis_dict.redis_type,
                    deviceID=device_id,
                    value=serialized_json_state.encode("utf-8", ),
                    version=redis_version,
                )

                logging.debug(
                    "key with version, %s contains: %s",
                    in_mem_key,
                    serialized_json_state,
                )
                states_to_report.append(state_proto)

        if len(states_to_report) == 0:
            logging.debug("Not replicating state. No state has changed!")
            return None
        return ReportStatesRequest(states=states_to_report)
Example #7
0
        async def test():
            get_grpc_mock.return_value = self.channel

            # Add initial state to be replicated
            self.nid_client.clear()
            self.idlist_client.clear()
            self.log_client.clear()
            self.foo_client.clear()

            key = 'id1'
            key2 = 'id2'
            self.nid_client[key] = NetworkID(id='foo')
            self.idlist_client[key] = IDList(ids=['bar', 'blah'])
            # Increment version
            self.idlist_client[key] = IDList(ids=['bar', 'blah'])
            # Set state that will be 'unreplicated'
            self.log_client[key2] = LogVerbosity(verbosity=5)

            req = await self.state_replicator._collect_states_to_replicate()
            self.assertEqual(3, len(req.states))

            # Ensure in-memory map updates properly for successful replications
            await self.state_replicator._send_to_state_service(req)
            self.assertEqual(2, len(self.state_replicator._state_versions))
            mem_key1 = make_mem_key('id1', NID_TYPE)
            mem_key2 = make_mem_key(
                'aaa-bbb:id1',
                IDList_TYPE,
            )
            self.assertEqual(
                1,
                self.state_replicator._state_versions[mem_key1],
            )
            self.assertEqual(
                2,
                self.state_replicator._state_versions[mem_key2],
            )

            # Now run again, ensuring only the state the wasn't replicated
            # will be sent again
            req = await self.state_replicator._collect_states_to_replicate()
            self.assertEqual(1, len(req.states))
            self.assertEqual('aaa-bbb:id2', req.states[0].deviceID)
            self.assertEqual(LOG_TYPE, req.states[0].type)
Example #8
0
        async def test():
            get_grpc_mock.return_value = self.channel
            self.nid_client.clear()
            self.idlist_client.clear()
            self.log_client.clear()
            self.foo_client.clear()

            key = 'id1'
            # Set state that will be 'unsynced'
            self.nid_client[key] = NetworkID(id='foo')
            self.idlist_client[key] = IDList(ids=['bar', 'blah'])
            # Increment state's version
            self.idlist_client[key] = IDList(ids=['bar', 'blah'])

            await self.state_replicator._resync()
            self.assertEqual(True, self.state_replicator._has_resync_completed)
            self.assertEqual(1, len(self.state_replicator._state_versions))
            mem_key = make_mem_key('aaa-bbb:id1', IDList_TYPE)
            self.assertEqual(2, self.state_replicator._state_versions[mem_key])