Exemple #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:
        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())
Exemple #2
0
class SipPasswordHandler(_base.LoggedInHandler):
    @asynchronous
    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())

    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())

    def on_get_privates_failure(self, response):
        _log.error("Failed to get associated private ID from homestead %s", response)
        self.forward_error(response)

    def on_put_password_success(self, responses):
        self.finish({"sip_password": self.sip_password})

    def on_put_password_failure(self, response):
        _log.error("Failed to set password in homestead %s", response)
        self.forward_error(response)
Exemple #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())
Exemple #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())
Exemple #5
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())
Exemple #6
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())
Exemple #7
0
class RemoteProxyHandler(_base.LoggedInHandler):
    def __init__(self, application, request, **kwargs):
        """
           Abstract handler that proxies requests to a remote server (e.g.
           Homer or Homestead)

           Subclasses should override self.remote_get and self.remote_put
           with relevant methods for contacting remotes
        """
        super(RemoteProxyHandler, self).__init__(application, request,
                                                 **kwargs)
        # Using the request group approach as we may need to pull/push multiple docs
        # in the future
        self._request_group = None
        self.__response = None
        self.remote_name = None
        self.remote_get = None
        self.remote_put = None

    @asynchronous
    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())

    def _on_get_success(self, responses):
        _log.debug("Successfully fetched from %s" % self.remote_name)
        self.finish(responses[0].body)

    def _on_get_failure(self, response):
        _log.warn("Failed to fetch from %s" % self.remote_name)
        self.forward_error(response)

    @asynchronous
    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())

    def _on_put_success(self, responses):
        _log.debug("Successfully updated %s" % self.remote_name)
        self.finish(self.__response)

    def _on_put_failure(self, response):
        _log.warn("Failed to update %s" % self.remote_name)
        self.forward_error(response)
Exemple #8
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())
Exemple #9
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())
Exemple #10
0
class RemoteProxyHandler(_base.LoggedInHandler):
    def __init__(self, application, request, **kwargs):
        """
           Abstract handler that proxies requests to a remote server (e.g.
           Homer or Homestead)

           Subclasses should override self.remote_get and self.remote_put
           with relevant methods for contacting remotes
        """
        super(RemoteProxyHandler, self).__init__(application, request, **kwargs)
        # Using the request group approach as we may need to pull/push multiple docs
        # in the future
        self._request_group = None
        self.__response = None
        self.remote_name = None
        self.remote_get = None
        self.remote_put = None

    @asynchronous
    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())

    def _on_get_success(self, responses):
        _log.debug("Successfully fetched from %s" % self.remote_name)
        self.finish(responses[0].body)

    def _on_get_failure(self, response):
        _log.warn("Failed to fetch from %s" % self.remote_name)
        self.forward_error(response)

    @asynchronous
    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())

    def _on_put_success(self, responses):
        _log.debug("Successfully updated %s" % self.remote_name)
        self.finish(self.__response)

    def _on_put_failure(self, response):
        _log.warn("Failed to update %s" % self.remote_name)
        self.forward_error(response)
Exemple #11
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:
            _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())
Exemple #12
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())
Exemple #13
0
def _delete_number(db_sess, sip_uri, private_id, delete_digest, on_success, on_failure):
    """
       Deletes all information associated with a private/public identity
       pair, optionally deleting the digest associated with the private identity
    """
    numbers.remove_owner(db_sess, sip_uri)
    db_sess.commit()

    # Concurrently, delete data from Homestead and Homer
    request_group = HTTPCallbackGroup(on_success, on_failure)
    if delete_digest:
        homestead.delete_private_id(private_id, request_group.callback())
    homestead.delete_public_id(sip_uri, request_group.callback())
    xdm.delete_simservs(sip_uri, request_group.callback())
Exemple #14
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())
Exemple #15
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())
Exemple #16
0
class TestHTTPCallbackGroup(unittest.TestCase):
    def setUp(self):
        super(TestHTTPCallbackGroup, self).setUp()
        self.on_success = Mock()
        self.on_failure = Mock()
        self.group = HTTPCallbackGroup(self.on_success, self.on_failure)

    def test_get_callback(self):
        cb = self.group.callback()
        cb2 = self.group.callback()
        self.assertTrue(cb in self.group._live_callbacks)
        resp = mock_resp()
        cb(resp)
        self.assertFalse(cb in self.group._live_callbacks)
        self.assertTrue(cb2 in self.group._live_callbacks)
        self.assertTrue(resp in self.group.responses)

    def test_finish_success(self):
        cb = self.group.callback()
        cb2 = self.group.callback()
        self.assertFalse(self.on_failure.called)
        self.assertFalse(self.on_success.called)
        resp = mock_resp()
        cb(resp)
        self.assertFalse(self.on_failure.called)
        self.assertFalse(self.on_success.called)
        resp2 = mock_resp()
        cb2(resp2)
        self.assertFalse(self.on_failure.called)
        self.on_success.assert_called_once_with([resp, resp2])

    def test_finish_success_delete_404(self):
        cb = self.group.callback()
        cb2 = self.group.callback()
        self.assertFalse(self.on_failure.called)
        self.assertFalse(self.on_success.called)
        resp = mock_resp(code=404, method="DELETE")
        cb(resp)
        self.assertFalse(self.on_failure.called)
        self.assertFalse(self.on_success.called)
        resp2 = mock_resp()
        cb2(resp2)
        self.assertFalse(self.on_failure.called)
        self.on_success.assert_called_once_with([resp, resp2])

    def test_finish_failure(self):
        cb = self.group.callback()
        cb2 = self.group.callback()
        resp = mock_resp(404)
        cb(resp)
        self.on_failure.assert_called_once_with(resp)
        self.assertFalse(self.on_success.called)
        self.on_failure.reset_mock()
        resp2 = mock_resp()
        cb2(resp2)
        self.assertFalse(self.on_failure.called)
        self.assertFalse(self.on_success.called)
Exemple #17
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())
Exemple #18
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_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())
Exemple #19
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"]), self._on_get_failure)
            # 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())
Exemple #20
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())
Exemple #21
0
class SipPasswordHandler(_base.LoggedInHandler):
    @asynchronous
    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())

    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())

    def on_get_privates_failure(self, response):  # pragma: no cover
        _log.error("Failed to get associated private ID from homestead %s",
                   response)
        self.forward_error(response)

    def on_put_password_success(self, responses):
        self.finish({"sip_password": self.sip_password})

    def on_put_password_failure(self, response):  # pragma: no cover
        _log.error("Failed to set password in homestead %s", response)
        self.forward_error(response)
Exemple #22
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())
Exemple #23
0
class NumbersHandler(_base.LoggedInHandler):
    def __init__(self, application, request, **kwargs):
        super(NumbersHandler, self).__init__(application, request, **kwargs)
        self._request_group = None
        self.__response = None
        self.__failure_response = None
        self._numbers = None

    @asynchronous
    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"] = utils.format_phone_number(number["number"])

            _request_group = HTTPCallbackGroup(partial(self._on_get_success, number["sip_uri"]), self._on_get_failure)
            # 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())

    def _on_get_success(self, public_id, responses):
        _log.debug("Successfully fetched associated private identities")
        for response in responses:
            try:
                # Body is of format {"public_id": "<public_id>",
                #                    "private_ids": ["<private_id_1>", "<private_id_2>"...]}
                parsed_body = json.loads(response.body)
                # We only support one private id per public id, so only pull out first in list
                private_id = parsed_body["private_ids"][0]
                for number in [n for n in self._numbers if n["sip_uri"] == public_id]:
                    number["private_id"] = private_id

            except (TypeError, KeyError) as e:
                _log.error("Could not parse response: %s", response.body)
                self.send_error(httplib.BAD_GATEWAY,
                                reason="Upstream request failed: could not parse private identity list")
                return

        for number in self._numbers:
            if "private_id" not in number:
                _log.debug("Not all numbers have private IDs associated, not sending response to the browser yet...")
                return

        self.finish({"numbers": self._numbers})

    def _on_get_failure(self, response):
        _log.warn("Failed to fetch private identities from homestead")
        self.forward_error(response)

    @asynchronous
    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') == '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:
            # FIXME email operator to tell them we're out of numbers!
            _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 = utils.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()
            homestead.create_private_id(private_id,
                                        sip_password,
                                        self._request_group.callback())
            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(settings.SIP_DIGEST_REALM),
                                   public_callback)

        self.__response["private_id"] = private_id

        # Concurrently, store the default simservs in XDM.
        with open(settings.XDM_DEFAULT_SIMSERVS_FILE) as xml_file:
            default_xml = xml_file.read()
        xdm.put_simservs(sip_uri, default_xml, self._request_group.callback())

    def _on_post_success(self, responses):
        _log.debug("Successfully updated all the backends")
        self.finish(self.__response)

    def _on_post_failure(self, response):
        _log.warn("Failed to update all the backends")
        # Save off response so we can pass error through
        self.__failure_response = response
        # Try to back out the changes so we don't leave orphaned data.
        remove_public_id(self.db_session(), self.sip_uri,
                         self._on_backout_success, self._on_backout_failure)

    def _on_backout_success(self, responses):
        _log.warn("Backed out changes after failure")
        self.forward_error(self.__failure_response)

    def _on_backout_failure(self, responses):
        _log.warn("Failed to back out changes after failure")
        self.forward_error(self.__failure_response)
Exemple #24
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())
Exemple #25
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') == '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:
            # FIXME email operator to tell them we're out of numbers!
            _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 = utils.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()
            homestead.create_private_id(private_id,
                                        sip_password,
                                        self._request_group.callback())
            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(settings.SIP_DIGEST_REALM),
                                   public_callback)

        self.__response["private_id"] = private_id

        # Concurrently, store the default simservs in XDM.
        with open(settings.XDM_DEFAULT_SIMSERVS_FILE) as xml_file:
            default_xml = xml_file.read()
        xdm.put_simservs(sip_uri, default_xml, self._request_group.callback())
Exemple #26
0
class NumberHandler(_base.LoggedInHandler):
    def __init__(self, application, request, **kwargs):
        super(NumberHandler, self).__init__(application, request, **kwargs)
        self.__password_response = None
        self.__ifc_response = None
        self.__xdm_response = None

    @asynchronous
    def delete(self, username, sip_uri):
        """Deletes a given SIP URI."""
        _log.info("Request to delete %s by %s", sip_uri, username)
        user_id = self.get_and_check_user_id(username)
        self.check_number_ownership(sip_uri, user_id)
        # Set force_delete=False - if we can't remove the number from
        # Homestead/Homer, we'll keep the number assigned to the user
        # (who can delete it in future) rather than removing it and
        # leaving orphaned data in Homestead.
        remove_public_id(self.db_session(),
                         sip_uri,
                         self._on_delete_success,
                         self._on_delete_failure,
                         force_delete=False)

    def _on_delete_success(self, responses):
        _log.debug("All requests successful.")
        self.finish({})

    def _on_delete_failure(self, response):  # pragma: no cover
        _log.debug("At least one request failed.")
        self.forward_error(response)

    @asynchronous
    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())

    def _on_post_success(self, responses):  # pragma: no cover
        _log.debug("Successfully updated all the backends")
        self.finish(self.__response)

    def _on_post_failure(self, response):  # pragma: no cover
        _log.warn("Failed to update all the backends")
        # Save off response so we can pass error through
        self.__failure_response = response
        # Try to back out the changes so we don't leave orphaned data.
        # Set force_delete=True - this means that we remove the
        # partially-created line from Ellis even if Homestead is still
        # down and our DELETE requests aren't successful.
        remove_public_id(self.db_session(),
                         self.sip_uri,
                         self._on_backout_success,
                         self._on_backout_failure,
                         force_delete=True)
Exemple #27
0
class NumbersHandler(_base.LoggedInHandler):
    def __init__(self, application, request, **kwargs):
        super(NumbersHandler, self).__init__(application, request, **kwargs)
        self._request_group = None
        self.__response = None
        self.__failure_response = None
        self._numbers = None

    @asynchronous
    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())

    def _on_get_success(self, public_id, responses):
        _log.debug("Successfully fetched associated private identities")
        for response in responses:
            try:
                # Body is of format {"public_id": "<public_id>",
                #                    "private_ids": ["<private_id_1>", "<private_id_2>"...]}
                parsed_body = json.loads(response.body)
                # We only support one private id per public id, so only pull out first in list
                private_id = parsed_body["private_ids"][0]
                for number in [
                        n for n in self._numbers if n["sip_uri"] == public_id
                ]:
                    number["private_id"] = private_id

            except (TypeError, KeyError):  # pragma: no cover
                _log.error("Could not parse response: %s", response.body)
                self.send_error(
                    httplib.BAD_GATEWAY,
                    reason=
                    "Upstream request failed: could not parse private identity list"
                )
                return

        for number in self._numbers:
            if "private_id" not in number:
                _log.debug(
                    "Not all numbers have private IDs associated, not sending response to the browser yet..."
                )
                return

        self.finish({"numbers": self._numbers})

    def _on_get_failure(self, sip_uri, response):  # pragma: no cover
        _log.warn("Failed to fetch private identities from homestead for %s",
                  sip_uri)
        if hasattr(response, 'code') and response.code == 404:
            # The number has no records in Homestead, so forget about it locally
            _log.warn("Returning %s to the pool", sip_uri)
            db_sess = self.db_session()
            numbers.remove_owner(db_sess, sip_uri)
            db_sess.commit()
            # Also try and remove it from Homer, but do nothing if we fail
            xdm.delete_simservs(sip_uri, lambda responses: None)

        self.forward_error(response)

    @asynchronous
    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())

    def _on_post_success(self, responses):
        _log.debug("Successfully updated all the backends")
        self.finish(self.__response)

    def _on_post_failure(self, response):
        _log.warn("Failed to update all the backends")
        # Save off response so we can pass error through
        self.__failure_response = response
        # Try to back out the changes so we don't leave orphaned data.
        # Try to back out the changes so we don't leave orphaned data.
        # Set force_delete=True - this means that we remove the
        # partially-created line from Ellis even if Homestead is still
        # down and our DELETE requests aren't successful.
        remove_public_id(self.db_session(),
                         self.sip_uri,
                         self._on_backout_success,
                         self._on_backout_failure,
                         force_delete=True)

    def _on_backout_success(self, responses):  # pragma: no cover
        _log.warn("Backed out changes after failure")
        self.forward_error(self.__failure_response)

    def _on_backout_failure(self, responses):  # pragma: no cover
        _log.warn("Failed to back out changes after failure")
        self.forward_error(self.__failure_response)
Exemple #28
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())
Exemple #29
0
    def post(self, username, sip_uri):
        """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.
        with open(settings.XDM_DEFAULT_SIMSERVS_FILE) as xml_file:
            default_xml = xml_file.read()
        xdm.put_simservs(sip_uri, default_xml, self._request_group.callback())
Exemple #30
0
class NumberHandler(_base.LoggedInHandler):
    def __init__(self, application, request, **kwargs):
        super(NumberHandler, self).__init__(application, request, **kwargs)
        self.__password_response = None
        self.__ifc_response = None
        self.__xdm_response = None

    @asynchronous
    def delete(self, username, sip_uri):
        """Deletes a given SIP URI."""
        _log.info("Request to delete %s by %s", sip_uri, username)
        user_id = self.get_and_check_user_id(username)
        self.check_number_ownership(sip_uri, user_id)
        # Set force_delete=False - if we can't remove the number from
        # Homestead/Homer, we'll keep the number assigned to the user
        # (who can delete it in future) rather than removing it and
        # leaving orphaned data in Homestead.
        remove_public_id(
            self.db_session(), sip_uri, self._on_delete_success, self._on_delete_failure, force_delete=False
        )

    def _on_delete_success(self, responses):
        _log.debug("All requests successful.")
        self.finish({})

    def _on_delete_failure(self, response):
        _log.debug("At least one request failed.")
        self.forward_error(response)

    @asynchronous
    def post(self, username, sip_uri):
        """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.
        with open(settings.XDM_DEFAULT_SIMSERVS_FILE) as xml_file:
            default_xml = xml_file.read()
        xdm.put_simservs(sip_uri, default_xml, self._request_group.callback())

    def _on_post_success(self, responses):
        _log.debug("Successfully updated all the backends")
        self.finish(self.__response)

    def _on_post_failure(self, response):
        _log.warn("Failed to update all the backends")
        # Save off response so we can pass error through
        self.__failure_response = response
        # Try to back out the changes so we don't leave orphaned data.
        # Set force_delete=True - this means that we remove the
        # partially-created line from Ellis even if Homestead is still
        # down and our DELETE requests aren't successful.
        remove_public_id(
            self.db_session(), self.sip_uri, self._on_backout_success, self._on_backout_failure, force_delete=True
        )
Exemple #31
0
 def setUp(self):
     super(TestHTTPCallbackGroup, self).setUp()
     self.on_success = Mock()
     self.on_failure = Mock()
     self.group = HTTPCallbackGroup(self.on_success, self.on_failure)