def sources_network_info(source_id, auth_header): """ Get additional sources context from Sources REST API. Additional details retrieved from the network includes: - Source Name - Source ID Type -> AWS, Azure, or OCP - Authentication: OCP -> Source uid; AWS -> Network call to Sources Authentication Store Details are stored in the Sources database table. Args: source_id (Integer): Source identifier auth_header (String): Authentication Header. Returns: None """ sources_network = SourcesHTTPClient(auth_header, source_id) source_details = sources_network.get_source_details() source_name = source_details.get("name") source_type_id = int(source_details.get("source_type_id")) source_uuid = source_details.get("uid") source_type_name = sources_network.get_source_type_name(source_type_id) endpoint_id = sources_network.get_endpoint_id() if not endpoint_id and source_type_name != SOURCES_OCP_SOURCE_NAME: LOG.warning(f"Unable to find endpoint for Source ID: {source_id}") return source_type = SOURCE_PROVIDER_MAP.get(source_type_name) if not source_type: LOG.warning(f"Unexpected source type ID: {source_type_id}") return storage.add_provider_sources_network_info(source_id, source_uuid, source_name, source_type, endpoint_id) save_auth_info(auth_header, source_id)
def cost_mgmt_msg_filter(msg_data): """Verify that message is for cost management.""" event_type = msg_data.get("event_type") auth_header = msg_data.get("auth_header") if event_type in (KAFKA_APPLICATION_DESTROY, KAFKA_SOURCE_DESTROY): return msg_data if event_type in (KAFKA_AUTHENTICATION_CREATE, KAFKA_AUTHENTICATION_UPDATE): sources_network = SourcesHTTPClient(auth_header) source_id = sources_network.get_source_id_from_endpoint_id( msg_data.get("resource_id")) msg_data["source_id"] = source_id if not sources_network.get_application_type_is_cost_management( source_id): LOG.info( f"Resource id {msg_data.get('resource_id')} not associated with cost-management." ) return None else: source_id = msg_data.get("source_id") sources_network = SourcesHTTPClient(auth_header, source_id=source_id) source_details = sources_network.get_source_details() source_type_id = int(source_details.get("source_type_id")) source_type_name = sources_network.get_source_type_name(source_type_id) if source_type_name not in ( SOURCES_OCP_SOURCE_NAME, SOURCES_AWS_SOURCE_NAME, SOURCES_AWS_LOCAL_SOURCE_NAME, SOURCES_AZURE_SOURCE_NAME, SOURCES_AZURE_LOCAL_SOURCE_NAME, ): LOG.debug(f"Filtering unexpected source type {source_type_name}.") return None return msg_data
class SourceStatus: """Source Status.""" def __init__(self, source_id): """Initialize source id.""" self.source_id = source_id self.source = Sources.objects.get(source_id=source_id) if not source_settings_complete( self.source) or self.source.pending_delete: raise ObjectDoesNotExist( f"Source ID: {self.source_id} not ready for status") self.sources_client = SourcesHTTPClient(self.source.auth_header, source_id=source_id) @property def sources_response(self): return self.sources_client.build_source_status(self.status()) def _set_provider_active_status(self, active_status): """Set provider active status.""" if self.source.koku_uuid: try: provider = Provider.objects.get(uuid=self.source.koku_uuid) provider.active = active_status provider.save() except Provider.DoesNotExist: LOG.info( f"No provider found for Source ID: {self.source.source_id}" ) def determine_status(self, provider_type, source_authentication, source_billing_source): """Check cloud configuration status.""" interface = ProviderAccessor(provider_type) error_obj = None try: if self.source.account_id not in settings.DEMO_ACCOUNTS: interface.cost_usage_source_ready(source_authentication, source_billing_source) self._set_provider_active_status(True) except ValidationError as validation_error: self._set_provider_active_status(False) error_obj = validation_error self.source.refresh_from_db() return error_obj def status(self): """Find the source's availability status.""" source_billing_source = self.source.billing_source.get( "data_source") or {} source_authentication = self.source.authentication.get( "credentials") or {} provider_type = self.source.source_type return self.determine_status(provider_type, source_authentication, source_billing_source) @transaction.atomic def update_source_name(self): """Update source name if it is out of sync with platform.""" source_details = self.sources_client.get_source_details() if source_details.get("name") != self.source.name: self.source.name = source_details.get("name") self.source.save() builder = SourcesProviderCoordinator(self.source_id, self.source.auth_header) builder.update_account(self.source) def push_status(self): """Push status_msg to platform sources.""" try: status_obj = self.status() if self.source.source_type in (Provider.PROVIDER_GCP, Provider.PROVIDER_GCP_LOCAL): builder = SourcesProviderCoordinator(self.source.source_id, self.source.auth_header) if not status_obj: if self.source.koku_uuid: builder.update_account(self.source) elif self.source.billing_source.get("data_source", {}).get("table_id"): builder.create_account(self.source) self.sources_client.set_source_status(status_obj) self.update_source_name() LOG.info( f"Source status for Source ID: {str(self.source_id)}: Status: {str(status_obj)}" ) except SkipStatusPush as error: LOG.info( f"Platform sources status push skipped. Reason: {str(error)}") except SourcesHTTPClientError as error: err_msg = "Unable to push source status. Reason: {}".format( str(error)) LOG.warning(err_msg)