Esempio n. 1
0
def genTestClient(nodes: TestNodeSet = None,
                  nodeReg=None,
                  tmpdir=None,
                  signer=None) -> TestClient:
    nReg = nodeReg
    if nodeReg:
        assert isinstance(nodeReg, dict)
    elif hasattr(nodes, "nodeReg"):
        nReg = nodes.nodeReg.extractCliNodeReg()
    else:
        error("need access to nodeReg")

    for k, v in nReg.items():
        assert type(k) == str
        assert type(v) == HA

    ha = genHa()
    clientId = "testClient{}".format(ha.port)

    signer = signer if signer else SimpleSigner(clientId)

    tc = TestClient(clientId, nodeReg=nReg, ha=ha, basedirpath=tmpdir, signer=signer)
    if nodes:
        bootstrapClientKeys(tc, nodes)
    return tc
Esempio n. 2
0
    def addNode(self, name: str) -> TestNode:

        if name in self.nodes:
            error("{} already added".format(name))

        assert name in self.nodeReg
        ha, cliname, cliha = self.nodeReg[name]

        # nstack = dict(name=name,
        #               ha=ha,
        #               main=True,
        #               auto=auto if auto is not None else AutoMode.always)
        #
        # # TODO Should the `auto` for client stack always be `AutoMode.always`
        # cstack = dict(name=cliname,
        #               ha=cliha,
        #               main=True,
        #               auto=AutoMode.always)  # client stack is promiscuous, for now

        node = self.enter_context(
                TestNode(name=name,
                         ha=ha,
                         clientAuthNr=SimpleAuthNr(),
                         cliname=cliname,
                         cliha=cliha,
                         nodeRegistry=copy(self.nodeReg),
                         basedirpath=self.tmpdir,
                         primaryDecider=self.primaryDecider))
        self.nodes[name] = node
        self.__dict__[name] = node
        return node
Esempio n. 3
0
def checkDblImp():
    """
    Added this because I spent the better part of an evening troubleshooting an
    issue cause by double import. We were importing test.helper in one
    place, and test_helper in another, and python sees them as two different
    modules, and imported the same file twice. This caused genHa to be loaded
    twice, which caused overlapping ports to be assigned. Took a long time to
    track this down. I'm sure there's a better way to do this, but this seems
    to work for the basic testing I did.
    """
    logging.info("-------------checking for double imports-------------")
    ignore = {'posixpath.py',
              'helpers/pydev/pydevd.py',
              'importlib/_bootstrap.py',
              'importlib/_bootstrap_external.py',
              'helpers/pycharm/pytestrunner.py',
              'test/__init__.py',  # TODO why is this loaded more than once?
              'site-packages/pytest.py',
              'python3.5/os.py',
              'python3.5/re.py'}

    files = [x.__file__ for x in list(sys.modules.values())
             if hasattr(x, "__file__")]
    dups = set([x for x in files if files.count(x) > 1])
    ignoreddups = {d for d in dups for i in ignore if i in d}
    filtereddups = dups - ignoreddups
    if filtereddups:
        error("Doubly imported files detected {}".format(filtereddups))
Esempio n. 4
0
def getPrimaryReplica(nodes: Sequence[TestNode],
                      instId: int = 0) -> TestReplica:
    preplicas = [node.replicas[instId] for node in nodes if
                 node.replicas[instId].isPrimary]
    if len(preplicas) > 1:
        error("More than one primary node found")
    elif len(preplicas) < 1:
        error("No primary node found")
    else:
        return preplicas[0]
def malign3PhaseSendingMethod(replica: TestReplica, msgType: ThreePhaseMsg,
                              evilMethod):
    evilMethod = types.MethodType(evilMethod, replica)

    if msgType == PrePrepare:
        replica.sendPrePrepare = evilMethod
    elif msgType == Prepare:
        replica.sendPrepare = evilMethod
    elif msgType == Commit:
        replica.sendCommit = evilMethod
    else:
        util.error("Not a 3 phase message")
Esempio n. 6
0
    def newStack(cls, stack):
        """
        Create a new instance of the given RoadStackClass

        :param stack: a dictionary of Roadstack constructor arguments.
        :return: the new instance of stack created.
        """
        stk = cls(**stack)
        if stk.ha[1] != stack["ha"].port:
            error("the stack port number has changed, likely due to " "information in the keep")
        logger.info(
            "stack {} starting at {} in {} mode".format(stk.name, stk.ha, stk.keep.auto.name), extra={"cli": False}
        )
        return stk
Esempio n. 7
0
    def __init__(self,
                 names: Iterable[str] = None,
                 count: int = None,
                 nodeReg=None,
                 tmpdir=None,
                 keyshare=True,
                 primaryDecider=None):

        self.tmpdir = tmpdir

        super().__init__()

        self.primaryDecider = primaryDecider

        self.nodes = OrderedDict()  # type: Dict[str, TestNode]
        # Can use just self.nodes rather than maintaining a separate dictionary
        # but then have to pluck attributes from the `self.nodes` so keeping
        # it simple a the cost of extra memory and its test code so not a big
        # deal

        if nodeReg:
            self.nodeReg = nodeReg
        else:
            nodeNames = (names if names is not None and count is None else
                         genNodeNames(count) if count is not None else
                         error("only one of either names or count is required"))
            self.nodeReg = genNodeReg(
                    names=nodeNames)  # type: Dict[str, NodeDetail]
        for name in self.nodeReg.keys():
            node = self.addNode(name)

        # The following lets us access the nodes by name as attributes of the
        # NodeSet. It's not a problem unless a node name shadows a member.
        self.__dict__.update(self.nodes)
Esempio n. 8
0
    def reconcileNodeReg(self):
        """
        Handle remotes missing from the node registry and clean up old remotes no longer in this node's registry.

        :return: the missing remotes
        """
        matches = set()  # good matches found in nodestack remotes
        legacy = set()  # old remotes that are no longer in registry
        conflicts = set()  # matches found, but the ha conflicts
        logging.debug("{}'s nodereg is {}".format(self, self.nodeReg.items()))
        logging.debug("{}'s nodestack is {}".format(self, self.nodestack.remotes.values()))
        for r in self.nodestack.remotes.values():
            if r.name in self.nodeReg:
                if r.ha == self.nodeReg[r.name]:
                    matches.add(r.name)
                    logging.debug("matched remote is {} {}".format(r.uid, r.ha))
                else:
                    conflicts.add((r.name, r.ha))
                    error("ha for {} doesn't match".format(r.name))
            else:
                regName = [nm for nm, ha in self.nodeReg.items() if ha == r.ha]
                logging.debug("unmatched remote is {} {}".format(r.uid, r.ha))
                # assert len(regName) == 1
                if regName:
                    logger.debug(
                        "forgiving name mismatch for {} with same "
                        "ha {} using another name {}".format(regName, r.ha, r.name)
                    )
                    matches.add(regName[0])
                else:
                    logger.debug("{} found a legacy remote {} " "without a matching ha {}".format(self, r.name, r.ha))
                    legacy.add(r)

        # missing from remotes... need to connect
        missing = set(nm for nm, ha in self.nodeReg.items() if nm not in matches)

        if len(missing) + len(matches) + len(conflicts) != len(self.nodeReg):
            logger.error("Error reconciling nodeReg with remotes")
            logger.error("missing: {}".format(missing))
            logger.error("matches: {}".format(matches))
            logger.error("conflicts: {}".format(conflicts))
            logger.error("nodeReg: {}".format(self.nodeReg.keys()))
            error("Error reconciling nodeReg with remotes; see logs")

        if conflicts:
            error("found conflicting address information {} in registry".format(conflicts))
        if legacy:
            for l in legacy:
                logger.error(
                    "{} found legacy entry [{}, {}] in remotes, " "that were not in registry".format(self, l.name, l.ha)
                )

                # TODO Remove this. Why are we raising error. Someone might
                # attempt to connect to a node and might end up in its nodestack

                # error("found legacy entries {} in remotes, that were not "
                #       "in registry".format(legacy))
                # this could happen if we are somehow re-using the same temp directory
        return missing
Esempio n. 9
0
 def getNodeName(node: NodeRef) -> str:
     return node if isinstance(node, str) \
         else node.name if isinstance(node, Node) \
         else error("Expected a node or node name")
Esempio n. 10
0
 def getNode(self, node: NodeRef) -> TestNode:
     return node if isinstance(node, Node) \
         else self.nodes.get(node) if isinstance(node, str) \
         else error("Expected a node or node name")