Repository: canonical/operator
Pull request #1197 (2024-04-24 01:02:08)

feat: add pebble.CheckInfo.change_id field
This is new with health checks being implemented as changes and tasks (https://github.com/canonical/pebble/pull/409).

Ops/charms will likely not use this new field. Even once we have the new `change-updated` event, that has a `.get_change()` method to get the change directly. But we're adding it to the Pebble client/types for completeness.

We shouldn't merge this before that Pebble PR is merged, just in case anything changes.


Patch:
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 7928bf3..b91bfc8 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -20,7 +20,7 @@ jobs:
     steps:
       - uses: actions/checkout@v3
       - name: Setup Python
-        uses: actions/setup-python@v1
+        uses: actions/setup-python@v5
       - name: Install build dependencies
         run: pip install wheel build
       - name: Build
diff --git a/ops/pebble.py b/ops/pebble.py
index 638885f..604c675 100644
--- a/ops/pebble.py
+++ b/ops/pebble.py
@@ -208,7 +208,8 @@ if TYPE_CHECKING:
                                 "level": NotRequired[Optional[Union['CheckLevel', str]]],
                                 "status": Union['CheckStatus', str],
                                 "failures": NotRequired[int],
-                                "threshold": int})
+                                "threshold": int,
+                                "change-id": NotRequired[str]})
     _FileInfoDict = TypedDict('_FileInfoDict',
                               {"path": str,
                                "name": str,
@@ -1268,6 +1269,13 @@ class CheckInfo:
     This is how many consecutive failures for the check to be considered "down".
     """
 
+    change_id: Optional[ChangeID]
+    """Change ID of ``perform-check`` or ``recover-check`` change driving this check.
+
+    This will be None on older versions of Pebble, which did not use changes
+    to drive health checks.
+    """
+
     def __init__(
         self,
         name: str,
@@ -1275,12 +1283,14 @@ class CheckInfo:
         status: Union[CheckStatus, str],
         failures: int = 0,
         threshold: int = 0,
+        change_id: Optional[ChangeID] = None,
     ):
         self.name = name
         self.level = level
         self.status = status
         self.failures = failures
         self.threshold = threshold
+        self.change_id = change_id
 
     @classmethod
     def from_dict(cls, d: '_CheckInfoDict') -> 'CheckInfo':
@@ -1299,15 +1309,17 @@ class CheckInfo:
             status=status,
             failures=d.get('failures', 0),
             threshold=d['threshold'],
+            change_id=ChangeID(d['change-id']) if 'change-id' in d else None,
         )
 
     def __repr__(self):
         return ('CheckInfo('
                 f'name={self.name!r}, '
-                f'level={self.level!r}, '
+                f'level={self.level}, '
                 f'status={self.status}, '
                 f'failures={self.failures}, '
-                f'threshold={self.threshold!r})'
+                f'threshold={self.threshold!r}, '
+                f'change_id={self.change_id!r})'
                 )
 
 


Test patch:
diff --git a/.github/workflows/framework-tests.yaml b/.github/workflows/framework-tests.yaml
index 64ec4ab..4832ba8 100644
--- a/.github/workflows/framework-tests.yaml
+++ b/.github/workflows/framework-tests.yaml
@@ -9,7 +9,7 @@ jobs:
     steps:
       - uses: actions/checkout@v3
       - name: Set up Python 3
-        uses: actions/setup-python@v2
+        uses: actions/setup-python@v5
         with:
           python-version: '3.11'
       - name: Install tox
@@ -24,7 +24,7 @@ jobs:
     steps:
       - uses: actions/checkout@v3
       - name: Set up Python 3
-        uses: actions/setup-python@v2
+        uses: actions/setup-python@v5
 
       - name: Install tox
         run: pip install tox~=4.2
@@ -39,11 +39,13 @@ jobs:
       matrix:
         os: [ubuntu-latest, macos-latest]
         python-version: ["3.8", "3.10"]
+        exclude:
+        - {python-version: "3.8", os: "macos-latest"}  # macos-14 is arm64, and there's no Python 3.8 build for arm64
 
     steps:
       - uses: actions/checkout@v3
       - name: Set up Python ${{ matrix.python-version }}
-        uses: actions/setup-python@v2
+        uses: actions/setup-python@v5
         with:
           python-version: ${{ matrix.python-version }}
 
@@ -64,7 +66,7 @@ jobs:
     steps:
       - uses: actions/checkout@v3
       - name: Set up Python ${{ matrix.python-version }}
-        uses: actions/setup-python@v2
+        uses: actions/setup-python@v5
         with:
           python-version: ${{ matrix.python-version }}
 
@@ -99,11 +101,13 @@ jobs:
       matrix:
         os: [ubuntu-latest, macos-latest]
         python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
+        exclude:
+        - {python-version: "3.8", os: "macos-latest"}  # macos-14 is arm64, and there's no Python 3.8 build for arm64
 
     steps:
       - uses: actions/checkout@v3
       - name: Set up Python 3
-        uses: actions/setup-python@v2
+        uses: actions/setup-python@v5
         with:
           python-version: ${{ matrix.python-version }}
 
diff --git a/.github/workflows/hello-charm-tests.yaml b/.github/workflows/hello-charm-tests.yaml
index c8032c2..ae8dc06 100644
--- a/.github/workflows/hello-charm-tests.yaml
+++ b/.github/workflows/hello-charm-tests.yaml
@@ -14,7 +14,7 @@ jobs:
 
     steps:
       - name: Set up Python 3.8
-        uses: actions/setup-python@v2
+        uses: actions/setup-python@v5
         with:
           python-version: "3.8"
 
diff --git a/.github/workflows/test-publish.yml b/.github/workflows/test-publish.yml
index cf9c562..1eea695 100644
--- a/.github/workflows/test-publish.yml
+++ b/.github/workflows/test-publish.yml
@@ -17,7 +17,7 @@ jobs:
     steps:
       - uses: actions/checkout@v3
       - name: Setup Python
-        uses: actions/setup-python@v1
+        uses: actions/setup-python@v5
         with:
           python-version: "3.10"
       - name: Install wheel
diff --git a/test/test_pebble.py b/test/test_pebble.py
index 0408692..2a540df 100644
--- a/test/test_pebble.py
+++ b/test/test_pebble.py
@@ -1289,6 +1289,7 @@ class TestCheckInfo(unittest.TestCase):
         assert check.status == pebble.CheckStatus.UP
         assert check.failures == 0
         assert check.threshold == 3
+        assert check.change_id is None
 
         check = pebble.CheckInfo(
             name='chk2',
@@ -1296,12 +1297,14 @@ class TestCheckInfo(unittest.TestCase):
             status=pebble.CheckStatus.DOWN,
             failures=5,
             threshold=3,
+            change_id=pebble.ChangeID('10'),
         )
         assert check.name == 'chk2'
         assert check.level == pebble.CheckLevel.ALIVE
         assert check.status == pebble.CheckStatus.DOWN
         assert check.failures == 5
         assert check.threshold == 3
+        assert check.change_id == pebble.ChangeID('10')
 
         d: pebble._CheckInfoDict = {
             'name': 'chk3',
@@ -1314,6 +1317,7 @@ class TestCheckInfo(unittest.TestCase):
         assert check.status == pebble.CheckStatus.UP
         assert check.failures == 0
         assert check.threshold == 3
+        assert check.change_id is None
 
         check = pebble.CheckInfo.from_dict({
             'name': 'chk4',
@@ -1321,12 +1325,14 @@ class TestCheckInfo(unittest.TestCase):
             'status': pebble.CheckStatus.DOWN,
             'failures': 3,
             'threshold': 3,
+            'change-id': '42',
         })
         assert check.name == 'chk4'
         assert check.level == pebble.CheckLevel.UNSET
         assert check.status == pebble.CheckStatus.DOWN
         assert check.failures == 3
         assert check.threshold == 3
+        assert check.change_id == pebble.ChangeID('42')
 
 
 _bytes_generator = typing.Generator[bytes, typing.Any, typing.Any]