Skip to content

Commit

Permalink
Better MDM target artifact updates & DDM retries
Browse files Browse the repository at this point in the history
  • Loading branch information
np5 committed Feb 8, 2025
1 parent 3e63141 commit ca3970e
Show file tree
Hide file tree
Showing 18 changed files with 510 additions and 178 deletions.
111 changes: 75 additions & 36 deletions tests/mdm/test_artifacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -1035,31 +1035,6 @@ def test_update_target_artifact_no_reinstall(self, patched_datetime):
# no reinstall
self.assertEqual(da.installed_at, datetime(2001, 2, 3, 4, 5, 6))

@patch("zentral.contrib.mdm.artifacts.datetime")
def test_update_target_artifact_allow_reinstall(self, patched_datetime):
patched_datetime.utcnow.side_effect = (
datetime(2001, 2, 3, 4, 5, 6),
datetime(2002, 3, 4, 5, 6, 7),
)
_, profile_a, (profile_av,) = self._force_blueprint_artifact()
target = Target(self.enrolled_device)
target.update_target_artifact(profile_av, TargetArtifact.Status.INSTALLED)
da_qs = DeviceArtifact.objects.filter(
enrolled_device=self.enrolled_device,
artifact_version__artifact=profile_a,
)
self.assertEqual(da_qs.count(), 1)
da = da_qs.first()
self.assertEqual(da.artifact_version, profile_av)
self.assertEqual(da.status, TargetArtifact.Status.INSTALLED)
self.assertEqual(da.installed_at, datetime(2001, 2, 3, 4, 5, 6))
self.assertIsNone(da.os_version_at_install_time)
target.update_target_artifact(profile_av, TargetArtifact.Status.INSTALLED, allow_reinstall=True)
self.assertEqual(da_qs.count(), 1)
da.refresh_from_db()
# reinstall
self.assertEqual(da.installed_at, datetime(2002, 3, 4, 5, 6, 7))

@patch("zentral.contrib.mdm.artifacts.datetime")
def test_update_target_artifact_same_uii_no_reinstall(self, patched_datetime):
patched_datetime.utcnow.side_effect = (
Expand Down Expand Up @@ -1209,7 +1184,7 @@ def test_update_target_artifact_install_over_failed_update(self, patched_datetim
da.refresh_from_db()
# update
self.assertEqual(da.status, TargetArtifact.Status.INSTALLED)
self.assertEqual(da.installed_at, datetime(2001, 2, 3, 4, 5, 6))
self.assertEqual(da.installed_at, datetime(2002, 3, 4, 5, 6, 7))
self.assertEqual(da.os_version_at_install_time, "13.4.0")
self.assertEqual(da.unique_install_identifier, str(profile_av.pk))

Expand Down Expand Up @@ -1289,7 +1264,7 @@ def test_update_target_artifact_upgrade_over_failed_install(self, patched_dateti
self.assertNotEqual(da2, da)
self.assertEqual(da2.artifact_version, profile_av2)
self.assertEqual(da2.status, TargetArtifact.Status.INSTALLED)
self.assertEqual(da2.installed_at, datetime(2001, 2, 3, 4, 5, 6))
self.assertEqual(da2.installed_at, datetime(2002, 3, 4, 5, 6, 7))
self.assertEqual(da2.os_version_at_install_time, "13.4.0")
self.assertEqual(da2.unique_install_identifier, str(profile_av2.pk))

Expand Down Expand Up @@ -1345,17 +1320,39 @@ def test_update_target_artifact_failed_upgrade_over_failed_install(self, patched
# update_target_artifacts_from_status_report

@patch("zentral.contrib.mdm.artifacts.datetime")
def test_update_target_artifacts_from_status_report_installed(self, patched_datetime):
patched_datetime.utcnow.return_value = datetime(2001, 2, 3, 4, 5, 6)
_, profile_a, (profile_av,) = self._force_blueprint_artifact()
def test_update_target_artifacts_from_status_report_installed_updated(self, patched_datetime):
patched_datetime.utcnow.side_effect = [datetime(2001, 2, 3, 4, 5, 6),
datetime(2002, 3, 4, 5, 6, 7),
datetime(2003, 4, 5, 6, 7, 8),]
_, profile_a, (profile_av2, profile_av) = self._force_blueprint_artifact(version_count=2)
# v1
status_report = self._build_status_report([(profile_av, True, True, None)])
self.enrolled_device.os_version = "10.5.2"
target = Target(self.enrolled_device)
self.assertTrue(target.update_target_artifacts_with_status_report(status_report) is True)
serialized_av = target._serialized_target_artifacts[str(profile_a.pk)]["versions"][str(profile_av.pk)]
self.assertEqual(
serialized_av,
(TargetArtifact.Status.INSTALLED, datetime(2001, 2, 3, 4, 5, 6), (10, 5, 2))
(TargetArtifact.Status.INSTALLED, datetime(2001, 2, 3, 4, 5, 6), (10, 5, 2), 1)
)
# v2
status_report = self._build_status_report([(profile_av2, True, True, None)])
self.enrolled_device.os_version = "10.5.3"
target = Target(self.enrolled_device)
self.assertTrue(target.update_target_artifacts_with_status_report(status_report) is True)
serialized_av = target._serialized_target_artifacts[str(profile_a.pk)]["versions"][str(profile_av2.pk)]
self.assertEqual(
serialized_av,
(TargetArtifact.Status.INSTALLED, datetime(2002, 3, 4, 5, 6, 7), (10, 5, 3), 1)
)
# v2 again
self.enrolled_device.os_version = "10.5.4"
target = Target(self.enrolled_device)
self.assertTrue(target.update_target_artifacts_with_status_report(status_report) is False)
serialized_av = target._serialized_target_artifacts[str(profile_a.pk)]["versions"][str(profile_av2.pk)]
self.assertEqual(
serialized_av,
(TargetArtifact.Status.INSTALLED, datetime(2002, 3, 4, 5, 6, 7), (10, 5, 3), 1)
)

@patch("zentral.contrib.mdm.artifacts.datetime")
Expand All @@ -1369,13 +1366,14 @@ def test_update_target_artifacts_from_status_report_uninstalled(self, patched_da
serialized_av = target._serialized_target_artifacts[str(profile_a.pk)]["versions"][str(profile_av.pk)]
self.assertEqual(
serialized_av,
(TargetArtifact.Status.UNINSTALLED, None, (0, 0, 0))
(TargetArtifact.Status.UNINSTALLED, None, (0, 0, 0), 1)
)

@patch("zentral.contrib.mdm.artifacts.datetime")
def test_update_target_artifacts_from_status_report_failed(self, patched_datetime):
patched_datetime.utcnow.return_value = datetime(2001, 2, 3, 4, 5, 6)
def test_update_target_artifacts_from_status_report_failed_then_installed(self, patched_datetime):
patched_datetime.utcnow.side_effect = [datetime(2001, 2, 3, 4, 5, 6), datetime(2002, 3, 4, 5, 6, 7)]
_, profile_a, (profile_av,) = self._force_blueprint_artifact()
# failed
reasons = [{"details": {"Error": "Yolo Fomo"},
"description": "Configuration cannot be applied",
"code": "Error.ConfigurationCannotBeApplied"}]
Expand All @@ -1386,14 +1384,28 @@ def test_update_target_artifacts_from_status_report_failed(self, patched_datetim
serialized_av = target._serialized_target_artifacts[str(profile_a.pk)]["versions"][str(profile_av.pk)]
self.assertEqual(
serialized_av,
(TargetArtifact.Status.FAILED, None, (0, 0, 0))
(TargetArtifact.Status.FAILED, None, (0, 0, 0), 1)
)
self.assertEqual(
DeviceArtifact.objects.get(artifact_version=profile_av).extra_info,
{"reasons": reasons,
"valid": "invalid",
"active": True}
)
# installed
status_report = self._build_status_report([(profile_av, True, True, None)])
target = Target(self.enrolled_device)
self.assertTrue(target.update_target_artifacts_with_status_report(status_report) is True)
serialized_av = target._serialized_target_artifacts[str(profile_a.pk)]["versions"][str(profile_av.pk)]
self.assertEqual(
serialized_av,
(TargetArtifact.Status.INSTALLED, datetime(2002, 3, 4, 5, 6, 7), (10, 5, 2), 2)
)
self.assertEqual(
DeviceArtifact.objects.get(artifact_version=profile_av).extra_info,
{"valid": "valid",
"active": True}
)

def test_update_target_artifacts_from_status_report_cleanup(self):
_, profile_a, (profile_av,) = self._force_blueprint_artifact()
Expand All @@ -1408,9 +1420,31 @@ def test_update_target_artifacts_from_status_report_cleanup(self):
1
)
status_report = self._build_status_report([])
target = Target(self.enrolled_device)
self.assertTrue(target.update_target_artifacts_with_status_report(status_report) is True)
self.assertEqual(DeviceArtifact.objects.filter(enrolled_device=self.enrolled_device).count(), 0)

def test_update_target_artifacts_from_status_report_cleanup_two_then_one(self):
_, profile_a, (profile_av,) = self._force_blueprint_artifact()
_, profile_b, (profile_bv,) = self._force_blueprint_artifact()
# 2 installed
status_report = self._build_status_report([(profile_av, True, True, None),
(profile_bv, True, True, None)])
target = Target(self.enrolled_device)
self.assertTrue(target.update_target_artifacts_with_status_report(status_report) is True)
self.assertEqual(
set(target._serialized_target_artifacts.keys()),
set(str(a.pk) for a in (profile_a, profile_b))
)
# 1 installed
status_report = self._build_status_report([(profile_bv, True, True, None)])
target = Target(self.enrolled_device)
self.assertTrue(target.update_target_artifacts_with_status_report(status_report) is True)
self.assertEqual(
set(target._serialized_target_artifacts.keys()),
set(str(a.pk) for a in (profile_b,))
)

def test_update_target_artifacts_from_status_report_missing_configurations_noop(self):
_, profile_a, (profile_av,) = self._force_blueprint_artifact()
target = Target(self.enrolled_device)
Expand Down Expand Up @@ -1506,7 +1540,12 @@ def test_update_device_target_with_status_report(self, send_enrolled_device_noti
send_enrolled_device_notification.assert_called_once_with(self.enrolled_device)

@patch("zentral.contrib.mdm.artifacts.send_enrolled_user_notification")
def test_update_user_target_with_status_report(self, send_enrolled_user_notification):
@patch("zentral.contrib.mdm.artifacts.post_target_artifact_update_events")
def test_update_user_target_with_status_report(
self,
post_target_artifact_update_events,
send_enrolled_user_notification
):
target = Target(self.enrolled_device, self.enrolled_user)
status_report = self._build_status_report([])
self.assertIsNone(target.client_capabilities)
Expand Down
16 changes: 10 additions & 6 deletions tests/mdm/test_declarations_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,23 @@ def test_get_artifact_version_server_token_reinstall_major(self):
target,
{"reinstall_on_os_update": str(Artifact.ReinstallOnOSUpdate.MAJOR),
"reinstall_interval": 0},
{"pk": av_pk}
{"pk": av_pk},
0
)
self.assertEqual(server_token, f"{av_pk}.ov-15")

def test_get_artifact_version_server_token_reinstall_minor(self):
def test_get_artifact_version_server_token_reinstall_minor_one_attempt_count(self):
target = Mock()
target.comparable_os_version = (15, 2, 1)
av_pk = str(uuid.uuid4())
server_token = get_artifact_version_server_token(
target,
{"reinstall_on_os_update": str(Artifact.ReinstallOnOSUpdate.MINOR),
"reinstall_interval": 0},
{"pk": av_pk}
{"pk": av_pk},
1
)
self.assertEqual(server_token, f"{av_pk}.ov-15.2")
self.assertEqual(server_token, f"{av_pk}.ov-15.2.ac-1")

def test_get_artifact_version_server_token_reinstall_patch(self):
target = Mock()
Expand All @@ -57,7 +59,8 @@ def test_get_artifact_version_server_token_reinstall_patch(self):
target,
{"reinstall_on_os_update": str(Artifact.ReinstallOnOSUpdate.PATCH),
"reinstall_interval": 0},
{"pk": av_pk}
{"pk": av_pk},
0
)
self.assertEqual(server_token, f"{av_pk}.ov-15.2.1")

Expand All @@ -73,6 +76,7 @@ def test_get_artifact_version_server_token_reinstall_interval(self, patched_date
target,
{"reinstall_on_os_update": str(Artifact.ReinstallOnOSUpdate.NO),
"reinstall_interval": 3600 * 24 * 90},
{"pk": av_pk}
{"pk": av_pk},
0
)
self.assertEqual(server_token, f"{av_pk}.ri-1")
Loading

0 comments on commit ca3970e

Please sign in to comment.