Пример #1
0
def _delete_number(db_sess, sip_uri, private_id, delete_digest, on_success,
                   on_failure, force_delete):
    """
       Deletes all information associated with a private/public identity
       pair, optionally deleting the digest associated with the private identity
    """
    def on_upstream_deletion(*args):
        _log.info(
            "Deletion from Homestead and Homer was OK - returning number to pool"
        )
        numbers.remove_owner(db_sess, sip_uri)
        db_sess.commit()
        on_success(args)

    # Concurrently, delete data from Homestead and Homer
    request_group = HTTPCallbackGroup(on_upstream_deletion, on_failure)

    if force_delete:  # pragma: no cover
        request_group = HTTPCallbackGroup(on_success, on_failure)
        _log.info(
            "Returning number to pool before attempting deletion from Homestead and Homer"
        )
        numbers.remove_owner(db_sess, sip_uri)
        db_sess.commit()

    if delete_digest:
        # Deleting the private ID will delete its associated IRS (and
        # therefore any subsidiary public IDs and their service profiles)
        homestead.delete_private_id(private_id, request_group.callback())
    else:
        homestead.delete_public_id(sip_uri, request_group.callback())
    xdm.delete_simservs(sip_uri, request_group.callback())
Пример #2
0
 def put(self, username, sip_uri):
     """Updates document on remote"""
     user_id = self.get_and_check_user_id(username)
     self.check_number_ownership(sip_uri, user_id)
     response_body = self.request.body
     self._request_group = HTTPCallbackGroup(self._on_put_success,
                                             self._on_put_failure)
     self.remote_put(sip_uri, response_body, self._request_group.callback())
Пример #3
0
    def get(self, username, sip_uri):
        """Fetches document from remote"""
        user_id = self.get_and_check_user_id(username)
        self.check_number_ownership(sip_uri, user_id)

        self._request_group = HTTPCallbackGroup(self._on_get_success,
                                                self._on_get_failure)
        self.remote_get(sip_uri, self._request_group.callback())
Пример #4
0
 def _on_get_privates_success(responses):
     _log.debug("Got related private ids")
     # Body is of format {"private_ids": ["<private_id_1>", "<private_id_2>"...]}
     parsed_body = json.loads(responses[0].body)
     # We only support one private id per public id, so only pull out first in list
     private_id = parsed_body["private_ids"][0]
     request_group2 = HTTPCallbackGroup(
         partial(_on_get_publics_success, private_id), on_failure)
     homestead.get_associated_publics(private_id, request_group2.callback())
Пример #5
0
def remove_public_id(db_sess, sip_uri, on_success, on_failure, force_delete):
    """
       Looks up the private id related to the sip_uri, and then the public ids
       related the retrieved private id. If there are multiple public ids, then
       only the sip_uri is is removed from Homestead, and the association to its
       private id is destroyed. If this is the only public id associated with the
       private id, then both the private and public ids are removed from Homestead
       along with their associations
    """
    def _on_get_privates_success(responses):
        _log.debug("Got related private ids")
        # Body is of format {"private_ids": ["<private_id_1>", "<private_id_2>"...]}
        parsed_body = json.loads(responses[0].body)
        # We only support one private id per public id, so only pull out first in list
        private_id = parsed_body["private_ids"][0]
        request_group2 = HTTPCallbackGroup(
            partial(_on_get_publics_success, private_id), on_failure)
        homestead.get_associated_publics(private_id, request_group2.callback())

    def _on_get_publics_success(private_id, responses):
        _log.debug("Got related public ids")
        parsed_body = json.loads(responses[0].body)
        public_ids = parsed_body["associated_public_ids"]
        if (utils.sip_public_id_to_private(sip_uri) == private_id
                and len(public_ids) > 1):
            # Do not permit deletion of an original public identity if others exist
            # otherwise another may claim the same private id from the pool
            _log.error(
                "Failed to delete default public ID %s while other IDs are attached to the same private ID"
                % sip_uri)
            _log.error("Other public IDs are %s" % ", ".join(public_ids))
            on_failure(responses[0])
        else:
            # Only delete the digest if there is only a single private identity
            # associated with our sip_uri (i.e. this is the last public id)
            delete_digest = (len(public_ids) == 1)
            _delete_number(db_sess, sip_uri, private_id, delete_digest,
                           on_success, on_failure, force_delete)

    def _on_get_privates_failure(response):
        if (response.code == 404) or force_delete:
            # The number has no records in Homestead
            _log.debug("Failed to retrieve private IDs for a public ID")
            _log.debug("Returning %s to the pool" % sip_uri)
            numbers.remove_owner(db_sess, sip_uri)
            db_sess.commit()
            on_success({})
        else:  # pragma: no cover
            _log.warn("Non-404 response - not returning number to pool")
            on_failure(response)

    request_group = HTTPCallbackGroup(_on_get_privates_success,
                                      _on_get_privates_failure)
    homestead.get_associated_privates(sip_uri, request_group.callback())
Пример #6
0
    def post(self, username, sip_uri):
        """Resets the password for the given SIP URI."""
        user_id = self.get_and_check_user_id(username)
        self.check_number_ownership(sip_uri, user_id)
        self.sip_digest_realm = utils.sip_uri_to_domain(sip_uri)
        self.sip_password = utils.generate_sip_password()

        # Fetch private ID from Homestead for this public ID
        self._request_group = HTTPCallbackGroup(self.on_get_privates_success,
                                                self.on_get_privates_failure)
        homestead.get_associated_privates(sip_uri,
                                          self._request_group.callback())
Пример #7
0
    def on_get_privates_success(self, responses):
        _log.debug("Got related private ids")
        # Body is of format {"public_id": "<public_id>",
        #                    "private_ids": ["<private_id_1>", "<private_id_2>"...]}
        parsed_body = json.loads(responses[0].body)
        # We only support one private id per public id, so only pull out first in list
        private_id = parsed_body["private_ids"][0]

        # Do not expect a response body, as long as there is no error, we are fine
        self._request_group = HTTPCallbackGroup(self.on_put_password_success,
                                                self.on_put_password_failure)
        homestead.put_password(private_id,
                               self.sip_digest_realm, self.sip_password,
                               self._request_group.callback())
Пример #8
0
    def get(self, username):
        """Retrieve list of phone numbers."""
        user_id = self.get_and_check_user_id(username)
        self._numbers = numbers.get_numbers(self.db_session(), user_id)
        if len(self._numbers) == 0:
            self.finish({"numbers": []})
            return

        for number in self._numbers:
            number["number_id"] = number["number_id"].hex
            number["sip_uri"] = number["number"]
            number["sip_username"] = utils.sip_uri_to_phone_number(
                number["number"])
            number["domain"] = utils.sip_uri_to_domain(number["number"])
            number["number"] = utils.sip_uri_to_phone_number(number["number"])
            number["formatted_number"] = format_phone_number(number["number"])

            _request_group = HTTPCallbackGroup(
                partial(self._on_get_success, number["sip_uri"]),
                partial(self._on_get_failure, number["sip_uri"]))
            # We only store the public identities in Ellis, and must query
            # Homestead for the associated private identities
            homestead.get_associated_privates(number["sip_uri"],
                                              _request_group.callback())
Пример #9
0
    def post(self, username, sip_uri):  # pragma: no cover
        """Allocate a phone number."""
        _log.debug("Specific number allocation API call (%s)", sip_uri)
        self.is_admin_request()
        user_id = self.get_and_check_user_id(username)
        db_sess = self.db_session()
        pstn = self.get_argument('pstn', 'false').lower() == 'true'
        private_id = self.get_argument('private_id', None)
        new_private_id = self.get_argument('new_private_id',
                                           'false').lower() == 'true'
        try:
            number_id = uuid.UUID(
                numbers.get_sip_uri_number_id(db_sess, sip_uri))
        except NotFound:
            # This SIP URI is not currently in the pool, so add it
            number_id = numbers.add_number_to_pool(db_sess, sip_uri, False,
                                                   True)
        numbers.allocate_specific_number(db_sess, user_id, number_id)
        self.sip_uri = sip_uri
        db_sess.commit()

        # Work out the response we'll send if the upstream requests
        # are successful.
        number = utils.sip_uri_to_phone_number(sip_uri)
        pretty_number = format_phone_number(number)
        self.__response = {
            "sip_uri": sip_uri,
            "sip_username": number,
            "number": number,
            "pstn": pstn,
            "formatted_number": pretty_number,
            "number_id": number_id.hex
        }

        # Generate a random password and store it in Homestead.
        _log.debug("Populating other servers...")
        self._request_group = HTTPCallbackGroup(self._on_post_success,
                                                self._on_post_failure)

        public_callback = self._request_group.callback()

        if private_id == None:
            # No private id was provided, so we need to create a new
            # digest in Homestead
            private_id = utils.sip_public_id_to_private(sip_uri)
            new_private_id = True

        if new_private_id:
            sip_password = utils.generate_sip_password()
            _log.debug("About to create private ID at Homestead")
            homestead.create_private_id(private_id,
                                        utils.sip_uri_to_domain(sip_uri),
                                        sip_password,
                                        self._request_group.callback())
            _log.debug("Created private ID at Homestead")

            self.__response["sip_password"] = sip_password
        self.__response["sip_username"] = private_id

        # Associate the new public identity with the private identity in Homestead
        # and store the iFCs in homestead.
        homestead.create_public_id(
            private_id, sip_uri,
            ifcs.generate_ifcs(utils.sip_uri_to_domain(sip_uri)),
            public_callback)

        self.__response["private_id"] = private_id

        # Concurrently, store the default simservs in XDM.
        xdm.put_simservs(sip_uri, simservs.default_simservs(),
                         self._request_group.callback())
Пример #10
0
    def post(self, username):
        """Allocate a phone number."""
        _log.debug("Number allocation API call (PSTN = %s)",
                   self.get_argument('pstn', 'false'))
        user_id = self.get_and_check_user_id(username)
        db_sess = self.db_session()
        pstn = self.get_argument('pstn', 'false').lower() == 'true'
        private_id = self.get_argument('private_id', None)
        try:
            number_id = numbers.allocate_number(db_sess, user_id, pstn)
            sip_uri = numbers.get_number(db_sess, number_id, user_id)
            self.sip_uri = sip_uri
            _log.debug("SIP URI %s", sip_uri)
            # FIXME We shouldn't commit until we know XDM/HS have succeeded but
            # if we hold the transaction open we can deadlock
            # * Request 1 comes in and allocates a number, kicks off requests
            #   to XDM/Homestead, has transaction open, returns thread to Tornado
            # * Request 2 comes in, allocates same number, can't lock it for
            #   update because Request 1 is holding it.  Blocks.
            # * Request 1 gets response but the thread is tied up
            # * Request 2 SQL transaction times out.
            # * Request 1 probably completes..
            db_sess.commit()
        except NotFound:  # pragma: no cover
            # FIXME email operator to tell them we're out of numbers!
            db_sess.rollback()
            _log.warning("No available numbers")
            raise HTTPError(httplib.SERVICE_UNAVAILABLE,
                            "No available numbers")

        # Work out the response we'll send if the upstream requests
        # are successful.
        number = utils.sip_uri_to_phone_number(sip_uri)
        pretty_number = format_phone_number(number)
        self.__response = {
            "sip_uri": sip_uri,
            "sip_username": number,
            "number": number,
            "pstn": pstn,
            "formatted_number": pretty_number,
            "number_id": number_id.hex
        }

        # Generate a random password and store it in Homestead.
        _log.debug("Populating other servers...")
        self._request_group = HTTPCallbackGroup(self._on_post_success,
                                                self._on_post_failure)

        public_callback = self._request_group.callback()

        if private_id == None:
            # No private id was provided, so we need to create a new
            # digest in Homestead
            private_id = utils.sip_public_id_to_private(sip_uri)
            sip_password = utils.generate_sip_password()
            _log.debug("About to create private ID at Homestead")
            homestead.create_private_id(private_id,
                                        utils.sip_uri_to_domain(sip_uri),
                                        sip_password,
                                        self._request_group.callback())
            _log.debug("Created private ID at Homestead")
            self.__response["sip_password"] = sip_password

        # Associate the new public identity with the private identity in Homestead
        # and store the iFCs in homestead.
        homestead.create_public_id(
            private_id, sip_uri,
            ifcs.generate_ifcs(utils.sip_uri_to_domain(sip_uri)),
            public_callback)

        self.__response["private_id"] = private_id

        # Concurrently, store the default simservs in XDM.
        xdm.put_simservs(sip_uri, simservs.default_simservs(),
                         self._request_group.callback())