From fb0f471db5b74f3692d600ac24d978bbe245cea7 Mon Sep 17 00:00:00 2001 From: Ioannis Foukarakis Date: Tue, 20 Aug 2024 11:24:24 +0300 Subject: [PATCH] MM-60179: add support package (#1580) * MM-60179: add support package * Fix linter issues, revert user survey * Fix linter issues * Rename support package to support packet --- .../metadata/invalid/missing_extras.yaml | 7 -- .../utils/fixtures/packets/support/full.yaml | 37 ++++++ .../fixtures/packets/support/invalid.yaml | 36 ++++++ .../packets/support/valid_with_metadata.zip | Bin 0 -> 52933 bytes .../support/valid_without_metadata.zip | Bin 0 -> 15713 bytes tests/utils/packets/test_loaders.py | 119 +++++++++++++++++- utils/packets/__main__.py | 16 ++- utils/packets/loaders.py | 28 +++++ utils/packets/models/metadata.py | 2 +- utils/packets/models/support.py | 117 +++++++++++++++++ utils/packets/service.py | 27 +++- 11 files changed, 374 insertions(+), 15 deletions(-) delete mode 100644 tests/utils/fixtures/packets/metadata/invalid/missing_extras.yaml create mode 100644 tests/utils/fixtures/packets/support/full.yaml create mode 100644 tests/utils/fixtures/packets/support/invalid.yaml create mode 100644 tests/utils/fixtures/packets/support/valid_with_metadata.zip create mode 100644 tests/utils/fixtures/packets/support/valid_without_metadata.zip create mode 100644 utils/packets/models/support.py diff --git a/tests/utils/fixtures/packets/metadata/invalid/missing_extras.yaml b/tests/utils/fixtures/packets/metadata/invalid/missing_extras.yaml deleted file mode 100644 index ead3cce7f..000000000 --- a/tests/utils/fixtures/packets/metadata/invalid/missing_extras.yaml +++ /dev/null @@ -1,7 +0,0 @@ -version: 1 -type: plugin-packet -generated_at: 1721728796871 -server_version: 9.11.0 -server_id: p7j6wmx6269jan410vjrylfb2u -license_id: 0ubekqbvxkptxoasnq1qdadkz1 -customer_id: jcvj1vkppgc7takujqe4449itu diff --git a/tests/utils/fixtures/packets/support/full.yaml b/tests/utils/fixtures/packets/support/full.yaml new file mode 100644 index 000000000..dec423585 --- /dev/null +++ b/tests/utils/fixtures/packets/support/full.yaml @@ -0,0 +1,37 @@ +license_to: Mattermost +server_os: linux +server_architecture: amd64 +server_version: 8.1.9 +build_hash: 4c83724516242843802cc75840b08ead6afbd37b +database_type: postgres +database_version: "13.10" +database_schema_version: "113" +active_users: 1 +license_supported_users: 200000 +total_channels: 2 +total_posts: 6 +total_teams: 1 +daily_active_users: 1 +monthly_active_users: 1 +websocket_connections: 0 +master_db_connections: 14 +read_db_connections: 0 +inactive_user_count: 0 +elastic_post_indexing_jobs: [] +elastic_post_aggregation_jobs: [] +ldap_sync_jobs: [] +message_export_jobs: [] +data_retention_jobs: [] +compliance_jobs: [] +migration_jobs: +- id: 4555h6cxb38q3rhnyfu95dypxh + type: migrations + priority: 0 + createat: 1723734966121 + startat: 1723734980530 + lastactivityat: 1723734981002 + status: success + progress: 0 + data: + last_done: '{"current_table":"ChannelMembers","last_team_id":"crro7gj13bdzfjm4rmm6ept6sa","last_channel_id":"mpmdxijsftdodkzbehncatthcr","last_user":"wg94o7yd4jyxjbxoihettwgmah"}' + migration_key: migration_advanced_permissions_phase_2 diff --git a/tests/utils/fixtures/packets/support/invalid.yaml b/tests/utils/fixtures/packets/support/invalid.yaml new file mode 100644 index 000000000..ee505d251 --- /dev/null +++ b/tests/utils/fixtures/packets/support/invalid.yaml @@ -0,0 +1,36 @@ +license_to: Mattermost +server_os: linux +server_architecture: amd64 +build_hash: 4c83724516242843802cc75840b08ead6afbd37b +database_type: postgres +database_version: "13.10" +database_schema_version: 113 +active_users: 1 +license_supported_users: 200000 +total_channels: 2 +total_posts: 6 +total_teams: 1 +daily_active_users: 1 +monthly_active_users: 1 +websocket_connections: 0 +master_db_connections: 14 +read_db_connections: 0 +inactive_user_count: 0 +elastic_post_indexing_jobs: [] +elastic_post_aggregation_jobs: [] +ldap_sync_jobs: [] +message_export_jobs: [] +data_retention_jobs: [] +compliance_jobs: [] +migration_jobs: +- id: 4555h6cxb38q3rhnyfu95dypxh + type: migrations + priority: 0 + createat: 1723734966121 + startat: 1723734980530 + lastactivityat: 1723734981002 + status: success + progress: 0 + data: + last_done: '{"current_table":"ChannelMembers","last_team_id":"crro7gj13bdzfjm4rmm6ept6sa","last_channel_id":"mpmdxijsftdodkzbehncatthcr","last_user":"wg94o7yd4jyxjbxoihettwgmah"}' + migration_key: migration_advanced_permissions_phase_2 diff --git a/tests/utils/fixtures/packets/support/valid_with_metadata.zip b/tests/utils/fixtures/packets/support/valid_with_metadata.zip new file mode 100644 index 0000000000000000000000000000000000000000..313292eafa564994cdd61e50ac85733c45cffcfd GIT binary patch literal 52933 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 EKR_~ndjJ3c literal 0 HcmV?d00001 diff --git a/tests/utils/fixtures/packets/support/valid_without_metadata.zip b/tests/utils/fixtures/packets/support/valid_without_metadata.zip new file mode 100644 index 0000000000000000000000000000000000000000..ef378e44a7a3708a840850f4e5c094d5ba94d70f GIT binary patch literal 15713 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 T@t;cYe~I-UiU5o6KX3mRYXPwp literal 0 HcmV?d00001 diff --git a/tests/utils/packets/test_loaders.py b/tests/utils/packets/test_loaders.py index 3d8872a90..f4b3eb906 100644 --- a/tests/utils/packets/test_loaders.py +++ b/tests/utils/packets/test_loaders.py @@ -1,4 +1,4 @@ -from datetime import date +from datetime import date, datetime, timezone from pathlib import Path import pandas as pd @@ -6,12 +6,20 @@ from pandas.testing import assert_frame_equal from pydantic import ValidationError -from utils.packets.loaders import load_metadata, load_user_survey, load_user_survey_package +from utils.packets.loaders import ( + load_metadata, + load_support_packet_file, + load_support_packet_info, + load_user_survey, + load_user_survey_package, +) from utils.packets.models.metadata import Extras, SupportPacketMetadata, SupportPacketTypeEnum +from utils.packets.models.support import JobV1 FIXTURE_DIR = Path(__file__).parent.parent / 'fixtures' / 'packets' METADATA_DIR = FIXTURE_DIR / 'metadata' SURVEY_DIR = FIXTURE_DIR / 'user_survey' +SUPPORT_DIR = FIXTURE_DIR / 'support' # @@ -78,7 +86,6 @@ def test_load_full_metadata(metadata, expected): [ pytest.param(METADATA_DIR / 'invalid' / 'invalid_timestamp.yaml', [('generated_at',)], id='invalid timestamp'), pytest.param(METADATA_DIR / 'invalid' / 'invalid_type.yaml', [('type',)], id='invalid type'), - pytest.param(METADATA_DIR / 'invalid' / 'missing_extras.yaml', [('extras',)], id='missing extras'), pytest.param( METADATA_DIR / 'invalid' / 'missing_fields.yaml', [('generated_at',), ('server_id',), ('server_version',)], @@ -233,3 +240,109 @@ def test_load_invalid_plugin_id(): # THEN: expect proper issue to be raised assert str(exc.value) == 'Not a user survey packet - packet type is com.mattermost.plugin' + + +# +# Support packet loader tests +# + + +def test_load_support_packet_full(): + # WHEN: attempt to load a full support packet + with open(SUPPORT_DIR / 'full.yaml', 'r') as fp: + sp = load_support_packet_info(fp) + + # THEN: expect support packet to be loaded correctly + assert sp.license_to == 'Mattermost' + assert sp.server_os == 'linux' + assert sp.server_architecture == 'amd64' + assert sp.build_hash == '4c83724516242843802cc75840b08ead6afbd37b' + assert sp.database_type == 'postgres' + assert sp.database_version == '13.10' + assert sp.database_schema_version == '113' + assert sp.active_users == 1 + assert sp.license_supported_users == 200000 + assert sp.total_channels == 2 + assert sp.total_posts == 6 + assert sp.total_teams == 1 + assert sp.daily_active_users == 1 + assert sp.monthly_active_users == 1 + assert sp.websocket_connections == 0 + assert sp.master_db_connections == 14 + assert sp.read_db_connections == 0 + assert sp.inactive_user_count == 0 + assert sp.elastic_post_indexing_jobs == [] + assert sp.elastic_post_aggregation_jobs == [] + assert sp.ldap_sync_jobs == [] + assert sp.message_export_jobs == [] + assert sp.data_retention_jobs == [] + assert sp.compliance_jobs == [] + assert sp.bleve_post_indexing_jobs is None + assert sp.migration_jobs == [ + JobV1( + id='4555h6cxb38q3rhnyfu95dypxh', + type='migrations', + priority=0, + createat=datetime(2024, 8, 15, 15, 16, 6, 121000, timezone.utc), + startat=datetime(2024, 8, 15, 15, 16, 20, 530000, timezone.utc), + lastactivityat=datetime(2024, 8, 15, 15, 16, 21, 2000, timezone.utc), + status='success', + progress=0, + data={ + 'last_done': '{"current_table":"ChannelMembers","last_team_id":"crro7gj13bdzfjm4rmm6ept6sa","last_channel_id":"mpmdxijsftdodkzbehncatthcr","last_user":"wg94o7yd4jyxjbxoihettwgmah"}', # noqa: E501 + 'migration_key': 'migration_advanced_permissions_phase_2', + }, + ) + ] + + +def test_support_packet_invalid(): + # WHEN: attempt to load an invalid support packet + with pytest.raises(ValidationError) as exc, open(SUPPORT_DIR / 'invalid.yaml', 'r') as fp: + load_support_packet_info(fp) + + assert sorted([e['loc'] for e in exc.value.errors()]) == [ + ('database_schema_version',), # Int instead of string + ('server_version',), # Missing + ] + + +# +# Full loader for support packet v1 +# + + +def test_load_full_support_packet_v1_with_metadata(): + # WHEN: attempt to load a valid support packet + metadata, sp = load_support_packet_file(SUPPORT_DIR / 'valid_with_metadata.zip') + + # THEN: expect metadata to be loaded correctly + assert metadata == SupportPacketMetadata( + version=1, + type=SupportPacketTypeEnum.support_packet, + generated_at=datetime(2024, 8, 19, 13, 46, 45, 94000, tzinfo=timezone.utc), + server_version='9.11.0', + server_id='rmg9ib5rspy93jxswyc454bwzo', + license_id='mud3ihm4938dxncqasxt14xxch', + customer_id='p9un369a67gimj4yd6i6ib39wh', + ) + + # THEN: expect responses to be loaded correctly + assert sp.license_to == 'Mattermost' + assert sp.server_os == 'linux' + assert sp.server_architecture == 'amd64' + assert sp.build_hash == '0bc2ddd42375a75ab14e63f038165150d4f07659' + + +def test_load_full_support_packet_v1_without_metadata(): + # WHEN: attempt to load a valid support packet + metadata, sp = load_support_packet_file(SUPPORT_DIR / 'valid_without_metadata.zip') + + # THEN: expect metadata to be loaded correctly + assert metadata is None + + # THEN: expect responses to be loaded correctly + assert sp.license_to == 'Mattermost' + assert sp.server_os == 'linux' + assert sp.server_architecture == 'amd64' + assert sp.build_hash == '4c83724516242843802cc75840b08ead6afbd37b' diff --git a/utils/packets/__main__.py b/utils/packets/__main__.py index 8c4213765..aacf7cc0b 100644 --- a/utils/packets/__main__.py +++ b/utils/packets/__main__.py @@ -3,7 +3,7 @@ import click from utils.helpers import initialize_cli_logging -from utils.packets.service import ingest_survey_packet +from utils.packets.service import ingest_support_packet, ingest_survey_packet initialize_cli_logging(logging.INFO, 'stderr') @@ -23,7 +23,19 @@ def user_survey( ) -> None: """ Ingest a user survey packet. - :param input: The zip file with the user survey packet data. """ ingest_survey_packet(input) + + +@packets.command() +@click.argument('input', type=click.Path(exists=True, dir_okay=False, readable=True, resolve_path=True)) +def support_v1( + input: click.Path, +) -> None: + """ + Ingest a support packet using the original support package specification. + + :param input: The zip file with the support package. + """ + ingest_support_packet(input) diff --git a/utils/packets/loaders.py b/utils/packets/loaders.py index 1384ccfd5..126691dd5 100644 --- a/utils/packets/loaders.py +++ b/utils/packets/loaders.py @@ -8,9 +8,11 @@ import yaml from utils.packets.models.metadata import SupportPacketMetadata +from utils.packets.models.support import SupportPacketV1 from utils.packets.models.user_survey import UserSurveyMetadata SUPPORT_PACKET_METADATA_FILE = 'metadata.yaml' +SUPPORT_PACKET_FILE = 'support_packet.yaml' SURVEY_METADATA_FILE = 'survey_metadata.json' SURVEY_DATA_FILE = 'responses.csv' @@ -80,3 +82,29 @@ def load_user_survey_package(user_survey_zip_file: str | os.PathLike) -> Tuple[S survey_data = load_user_survey(survey_metadata_fp, survey_data_fp) return metadata, survey_data + + +def load_support_packet_info(metadata_file: IO) -> SupportPacketV1: + """ + Load support packet from a YAML file. + """ + data = yaml.safe_load(metadata_file) + return SupportPacketV1(**data) + + +def load_support_packet_file( + support_packet_zip_file: str | os.PathLike, +) -> Tuple[SupportPacketMetadata, SupportPacketV1]: + with ZipFile(support_packet_zip_file, 'r') as zipfile: + + if SUPPORT_PACKET_METADATA_FILE in zipfile.namelist(): + # Metadata might not be present in older versions of the support packet + with zipfile.open(SUPPORT_PACKET_METADATA_FILE) as metadata_fp: + metadata = load_metadata(metadata_fp) + else: + metadata = None + + with zipfile.open(SUPPORT_PACKET_FILE) as packet_fp: + packet = load_support_packet_info(packet_fp) + + return metadata, packet diff --git a/utils/packets/models/metadata.py b/utils/packets/models/metadata.py index dbbb2de11..fc0a7ca93 100644 --- a/utils/packets/models/metadata.py +++ b/utils/packets/models/metadata.py @@ -24,4 +24,4 @@ class SupportPacketMetadata(BaseModel, extra='ignore'): server_id: str = Field(min_length=26, max_length=26) license_id: str | None = Field(None, min_length=0, max_length=26) customer_id: str | None = Field(None, min_length=0, max_length=26) - extras: Extras + extras: Extras | None = Field(None) diff --git a/utils/packets/models/support.py b/utils/packets/models/support.py new file mode 100644 index 000000000..83c5dff6e --- /dev/null +++ b/utils/packets/models/support.py @@ -0,0 +1,117 @@ +from datetime import datetime +from enum import Enum +from typing import List + +from pydantic import BaseModel, Field + + +class JobType(str, Enum): + data_retention = "data_retention" + message_export = "message_export" + elasticsearch_post_indexing = "elasticsearch_post_indexing" + elasticsearch_post_aggregation = "elasticsearch_post_aggregation" + bleve_post_indexing = "bleve_post_indexing" + ldap_sync = "ldap_sync" + migrations = "migrations" + plugins = "plugins" + expiry_notify = "expiry_notify" + product_notices = "product_notices" + active_users = "active_users" + import_process = "import_process" + import_delete = "import_delete" + export_process = "export_process" + export_delete = "export_delete" + cloud = "cloud" + resend_invitation_email = "resend_invitation_email" + extract_content = "extract_content" + last_accessible_post = "last_accessible_post" + last_accessible_file = "last_accessible_file" + upgrade_notify_admin = "upgrade_notify_admin" + trial_notify_admin = "trial_notify_admin" + post_persistent_notifications = "post_persistent_notifications" + install_plugin_notify_admin = "install_plugin_notify_admin" + hosted_purchase_screening = "hosted_purchase_screening" + s3_path_migration = "s3_path_migration" + cleanup_desktop_tokens = "cleanup_desktop_tokens" + delete_empty_drafts_migration = "delete_empty_drafts_migration" + refresh_post_stats = "refresh_post_stats" + delete_orphan_drafts_migration = "delete_orphan_drafts_migration" + export_users_to_csv = "export_users_to_csv" + delete_dms_preferences_migration = "delete_dms_preferences_migration" + + +class JobStatus(str, Enum): + pending = "pending" + in_progress = "in_progress" + success = "success" + error = "error" + cancel_requested = "cancel_requested" + canceled = "canceled" + warning = "warning" + + +class JobV1(BaseModel): + id: str + type: JobType + priority: int + createat: datetime + startat: datetime + lastactivityat: datetime + status: JobStatus + progress: int + data: dict + + +class SupportPacketV1(BaseModel): + # Based on https://github.com/mattermost/mattermost/blob/master/server/public/model/support_packet.go#L15 + server_os: str = Field(description="The operating system of the server") + server_architecture: str = Field(description="The architecture of the server, i.e. amd64") + server_version: str = Field(description="The version of the Mattermost server") + build_hash: str = Field(description="The build hash of the Mattermost server") + + # DB + database_type: str = Field(description="The type of database being used, i.e. postgres or mysql") + database_version: str = Field(description="The version of the database being used") + database_schema_version: str = Field(description="The schema version of the database being used") + websocket_connections: int = Field(description="The number of websocket connections") + master_db_connections: int = Field(description="The number of master database connections") + read_db_connections: int = Field(description="The number of read database connections") + + # Cluster + cluster_id: str | None = Field(None, description="The cluster ID, if server is running in cluster mode") + + # File store + file_driver: str | None = Field(None, description="The file store driver being used, i.e. local or s3") + file_status: str | None = Field(None, description="The status of the file store") + + # LDAP + ldap_vendor_name: str | None = Field(None) + ldap_verndor_version: str | None = Field(None) + + # ElasticSearch + elastic_server_version: str | None = Field(None) + elastic_server_plugins: str | None = Field(None) + + # License + license_to: str = Field(description="The name of the license owner, extracted from the license.") + license_supported_users: int = Field(description="The number of supported users in the license.") + license_is_trial: bool | None = Field(None, description="Whether the license is a trial license.") + + # Server Stats + active_users: int = Field(description="The number of unique active users") + daily_active_users: int = Field(description="The number of daily active users") + monthly_active_users: int = Field(description="The number of monthly active users") + inactive_user_count: int = Field(description="The number of inactive users") + total_posts: int = Field(description="The total number of posts") + total_channels: int = Field(description="The total number of channels") + total_teams: int = Field(description="The total number of teams") + + # Jobs + data_retention_jobs: List[JobV1] | None = Field(None, description="Data retention jobs") + bleve_post_indexing_jobs: List[JobV1] | None = Field(None, description="Bleve post indexing jobs") + message_export_jobs: List[JobV1] | None = Field(None, description="Message export jobs") + elastic_post_indexing_jobs: List[JobV1] | None = Field(None, description="Bleve post indexing jobs") + elastic_post_aggregation_jobs: List[JobV1] | None = Field(None, description="Elasticsearch post aggregation jobs") + ldap_sync_jobs: List[JobV1] | None = Field(None, description="LDAP sync jobs") + migration_jobs: List[JobV1] | None = Field(None, description="Migration jobs") + compliance_jobs: List[JobV1] | None = Field(None, description="Compliance jobs") diff --git a/utils/packets/service.py b/utils/packets/service.py index d04a91201..7f6961207 100644 --- a/utils/packets/service.py +++ b/utils/packets/service.py @@ -3,7 +3,7 @@ from click import ClickException -from utils.packets.loaders import UserSurveyFixedColumns, load_user_survey_package +from utils.packets.loaders import UserSurveyFixedColumns, load_support_packet_file, load_user_survey_package logger = getLogger(__name__) @@ -19,9 +19,32 @@ def ingest_survey_packet(survey_packet: str | os.PathLike): logger.info('Loaded survey packet') logger.info(f' -> Server ID: {metadata.server_id}') logger.info(f' -> License ID: {metadata.license_id}') - logger.info('\n') + logger.info('') logger.info(f' Total {df[UserSurveyFixedColumns.user_id.value].nunique()} unique users') # TODO: ingest in database except ValueError as e: raise ClickException(f'Error loading survey packet: {e}') + + +def ingest_support_packet(support_packet: str | os.PathLike): + """ + Load support package data and metadata. + + :support_package: The path to the survey packet file. + """ + try: + metadata, sp = load_support_packet_file(support_packet) + logger.info('Loaded support packet') + if metadata: + logger.info(f' -> Server ID: {metadata.server_id}') + logger.info(f' -> License ID: {metadata.license_id}') + else: + logger.info('Support packet does not include metadata file') + logger.info('') + logger.info(f' Server: {sp.server_version} ({sp.server_os} {sp.server_architecture})') + logger.info(f' Database: {sp.database_type} {sp.database_version} (schema {sp.database_schema_version})') + + # TODO: ingest in database + except ValueError as e: + raise ClickException(f'Error loading support package: {e}')