Пример #1
0
    def test_get_sources_authentication_fail_500(self, mock_get):
        """Assert get_authentication fails when response is not-200/404."""
        mock_get.return_value.status_code = http.HTTPStatus.INTERNAL_SERVER_ERROR
        with self.assertRaises(SourcesAPINotOkStatus):
            sources.get_authentication(self.account_number, self.authentication_id)

        mock_get.assert_called()
Пример #2
0
 def test_get_sources_authentication_fail_not_json(self, mock_get):
     """Assert get_authentication fails when response isn't JSON."""
     mock_get.return_value.status_code = http.HTTPStatus.OK
     mock_get.return_value.json.side_effect = json.decoder.JSONDecodeError(
         Mock(), MagicMock(), MagicMock()
     )
     with self.assertRaises(SourcesAPINotJsonContent):
         sources.get_authentication(self.account_number, self.authentication_id)
     mock_get.assert_called()
Пример #3
0
    def test_get_sources_authentication_not_found(self, mock_get):
        """Assert get_authentication returns None if not found."""
        mock_get.return_value.status_code = http.HTTPStatus.NOT_FOUND

        endpoint = sources.get_authentication(
            self.account_number, self.authentication_id
        )
        self.assertIsNone(endpoint)
        mock_get.assert_called()
Пример #4
0
    def test_get_sources_authentication_success(self, mock_get):
        """Assert get_authentication returns response content."""
        expected = {"hello": "world"}
        mock_get.return_value.status_code = http.HTTPStatus.OK
        mock_get.return_value.json.return_value = expected

        authentication = sources.get_authentication(
            self.account_number, self.authentication_id
        )
        self.assertEqual(authentication, expected)
        mock_get.assert_called()
Пример #5
0
def create_from_sources_kafka_message(message, headers):
    """
    Create our model objects from the Sources Kafka message.

    Because the Sources API may not always be available, this task must
    gracefully retry if communication with Sources fails unexpectedly.

    If this function succeeds, it spawns another async task to set up the
    customer's AWS account (configure_customer_aws_and_create_cloud_account).

    Args:
        message (dict): the "value" attribute of a message from a Kafka
            topic generated by the Sources service and having event type
            "ApplicationAuthentication.create"
        headers (list): the headers of a message from a Kafka topic
            generated by the Sources service and having event type
            "ApplicationAuthentication.create"

    """
    authentication_id = message.get("authentication_id", None)
    application_id = message.get("application_id", None)
    (
        account_number,
        platform_id,
    ) = sources.extract_ids_from_kafka_message(message, headers)

    if account_number is None or authentication_id is None or application_id is None:
        logger.error(_("Aborting creation. Incorrect message details."))
        return

    application = sources.get_application(account_number, application_id)
    if not application:
        logger.info(
            _("Application ID %(application_id)s for account number "
              "%(account_number)s does not exist; aborting cloud account creation."
              ),
            {
                "application_id": application_id,
                "account_number": account_number
            },
        )
        return

    application_type = application["application_type_id"]
    if application_type is not sources.get_cloudigrade_application_type_id(
            account_number):
        logger.info(
            _("Aborting creation. Application Type is not cloudmeter."))
        return

    authentication = sources.get_authentication(account_number,
                                                authentication_id)

    if not authentication:
        error_code = error_codes.CG2000
        error_code.log_internal_message(
            logger,
            {
                "authentication_id": authentication_id,
                "account_number": account_number
            },
        )
        error_code.notify(account_number, application_id)
        return

    authtype = authentication.get("authtype")
    if authtype not in settings.SOURCES_CLOUDMETER_AUTHTYPES:
        error_code = error_codes.CG2001
        error_code.log_internal_message(logger, {
            "authentication_id": authentication_id,
            "authtype": authtype
        })
        error_code.notify(account_number, application_id)
        return

    resource_type = authentication.get("resource_type")
    resource_id = authentication.get("resource_id")
    if resource_type != settings.SOURCES_RESOURCE_TYPE:
        error_code = error_codes.CG2002
        error_code.log_internal_message(logger, {
            "resource_id": resource_id,
            "account_number": account_number
        })
        error_code.notify(account_number, application_id)
        return

    source_id = application.get("source_id")
    arn = authentication.get("username") or authentication.get("password")

    if not arn:
        error_code = error_codes.CG2004
        error_code.log_internal_message(
            logger, {"authentication_id": authentication_id})
        error_code.notify(account_number, application_id)
        return

    with transaction.atomic():
        user, created = User.objects.get_or_create(username=account_number)
        if created:
            user.set_unusable_password()
            logger.info(
                _("User %s was not found and has been created."),
                account_number,
            )
            UserTaskLock.objects.get_or_create(user=user)

    # Conditionalize the logic for different cloud providers
    if authtype == settings.SOURCES_CLOUDMETER_ARN_AUTHTYPE:
        configure_customer_aws_and_create_cloud_account.delay(
            user.username,
            arn,
            authentication_id,
            application_id,
            source_id,
        )
Пример #6
0
def update_from_source_kafka_message(message, headers):
    """
    Update our model objects from the Sources Kafka message.

    Because the Sources API may not always be available, this task must
    gracefully retry if communication with Sources fails unexpectedly.

    This function is also decorated to retry if an unhandled `RuntimeError` is
    raised, which is the exception we raise in `rewrap_aws_errors` if we
    encounter an unexpected error from AWS. This means it should keep retrying
    if AWS is misbehaving.

    Args:
        message (dict): the "value" attribute of a message from a Kafka
            topic generated by the Sources service and having event type
            "Authentication.update"
        headers (list): the headers of a message from a Kafka topic
            generated by the Sources service and having event type
            "Authentication.update"

    """
    (
        account_number,
        authentication_id,
    ) = sources.extract_ids_from_kafka_message(message, headers)

    if account_number is None or authentication_id is None:
        logger.error(_("Aborting update. Incorrect message details."))
        return

    try:
        clount = CloudAccount.objects.get(
            platform_authentication_id=authentication_id)

        authentication = sources.get_authentication(account_number,
                                                    authentication_id)

        if not authentication:
            logger.info(
                _("Authentication ID %(authentication_id)s for account number "
                  "%(account_number)s does not exist; aborting cloud account update."
                  ),
                {
                    "authentication_id": authentication_id,
                    "account_number": account_number,
                },
            )
            return

        resource_type = authentication.get("resource_type")
        application_id = authentication.get("resource_id")
        if resource_type != settings.SOURCES_RESOURCE_TYPE:
            logger.info(
                _("Resource ID %(resource_id)s for account number %(account_number)s "
                  "is not of type Application; aborting cloud account update."
                  ),
                {
                    "resource_id": application_id,
                    "account_number": account_number
                },
            )
            return

        application = sources.get_application(account_number, application_id)
        source_id = application.get("source_id")

        arn = authentication.get("username") or authentication.get("password")
        if not arn:
            logger.info(
                _("Could not update CloudAccount with no ARN provided."))
            error_code = error_codes.CG2004
            error_code.log_internal_message(
                logger, {"authentication_id": authentication_id})
            error_code.notify(account_number, application_id)
            return

        # If the Authentication being updated is arn, do arn things.
        # The kafka message does not always include authtype, so we get this from
        # the sources API call
        if authentication.get(
                "authtype") == settings.SOURCES_CLOUDMETER_ARN_AUTHTYPE:
            update_aws_cloud_account(
                clount,
                arn,
                account_number,
                authentication_id,
                source_id,
            )
    except CloudAccount.DoesNotExist:
        # Is this authentication meant to be for us? We should check.
        # Get list of all app-auth objects and filter by our authentication
        response_json = sources.list_application_authentications(
            account_number, authentication_id)

        if response_json.get("meta").get("count") > 0:
            for application_authentication in response_json.get("data"):
                create_from_sources_kafka_message.delay(
                    application_authentication, headers)
        else:
            logger.info(
                _("The updated authentication with ID %s and account number %s "
                  "is not managed by cloud meter."),
                authentication_id,
                account_number,
            )