Skip to content

Commit 54acaa6

Browse files
authored
Merge branch 'main' into renovate/pydantic-1.x
2 parents 433d0e0 + 6eef365 commit 54acaa6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+103
-102
lines changed

.trivyignore

+2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
# Jenkins executable
22
CVE-2024-47072
3+
# Pebble vulnerabilities
4+
CVE-2024-45338

actions.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
get-admin-password:

charmcraft.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
type: charm

config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
options:

generate-src-docs.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env bash
22

3-
# Copyright 2024 Canonical Ltd.
3+
# Copyright 2025 Canonical Ltd.
44
# See LICENSE file for licensing details.
55

66
lazydocs --no-watermark --output-path src-docs src/*

jenkins_rock/rockcraft.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
name: jenkins

lib/charms/traefik_k8s/v2/ingress.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
r"""# Interface Library for ingress.

metadata.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
name: jenkins-k8s

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
[tool.bandit]

src/actions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Jenkins charm actions."""

src/agent.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""The Jenkins agent relation observer."""

src/auth_proxy.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Observer module for Jenkins to auth_proxy integration."""

src/charm.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python3
22

3-
# Copyright 2024 Canonical Ltd.
3+
# Copyright 2025 Canonical Ltd.
44
# See LICENSE file for licensing details.
55

66
"""Charm Jenkins."""

src/cos.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Observer module for Jenkins to COS integration."""

src/ingress.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Observer module for Jenkins to ingress integration."""

src/jenkins.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Functions to operate Jenkins."""

src/pebble.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Pebble functionality."""

src/state.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Jenkins States."""

src/timerange.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""The module for checking time ranges."""

templates/logging.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
# Use with java logging property

tests/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Tests module."""

tests/conftest.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Fixtures for jenkins-k8s charm tests."""

tests/integration/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Integration tests module."""

tests/integration/conftest.py

+11-23
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Fixtures for Jenkins-k8s-operator charm integration tests."""
@@ -19,7 +19,6 @@
1919
import requests
2020
from juju.action import Action
2121
from juju.application import Application
22-
from juju.client._definitions import FullStatus, UnitStatus
2322
from juju.model import Controller, Model
2423
from juju.unit import Unit
2524
from keycloak import KeycloakAdmin, KeycloakOpenIDConnection
@@ -38,7 +37,7 @@
3837
get_dex_service_url,
3938
update_redirect_uri,
4039
)
41-
from .helpers import generate_jenkins_client_from_application, get_pod_ip
40+
from .helpers import generate_jenkins_client_from_application, get_model_unit_addresses, get_pod_ip
4241
from .types_ import KeycloakOIDCMetadata, LDAPSettings, ModelAppUnit, UnitWebClient
4342

4443
KUBECONFIG = os.environ.get("TESTING_KUBECONFIG", "./kube-config")
@@ -129,13 +128,9 @@ def model_app_unit_fixture(model: Model, application: Application, unit: Unit):
129128
@pytest_asyncio.fixture(scope="module", name="unit_ip")
130129
async def unit_ip_fixture(model: Model, application: Application):
131130
"""Get Jenkins charm unit IP."""
132-
status: FullStatus = await model.get_status([application.name])
133-
try:
134-
unit_status: UnitStatus = next(iter(status.applications[application.name].units.values()))
135-
assert unit_status.address, "Invalid unit address"
136-
return unit_status.address
137-
except StopIteration as exc:
138-
raise StopIteration("Invalid unit status") from exc
131+
unit_ips = await get_model_unit_addresses(model=model, app_name=application.name)
132+
assert unit_ips, f"Unit IP address not found for {application.name}"
133+
return unit_ips[0]
139134

140135

141136
@pytest.fixture(scope="module", name="web_address")
@@ -480,15 +475,9 @@ async def jenkins_with_proxy_fixture(
480475
@pytest_asyncio.fixture(scope="module", name="proxy_jenkins_unit_ip")
481476
async def proxy_jenkins_unit_ip_fixture(model: Model, jenkins_with_proxy: Application):
482477
"""Get Jenkins charm w/ proxy enabled unit IP."""
483-
status: FullStatus = await model.get_status([jenkins_with_proxy.name])
484-
try:
485-
unit_status: UnitStatus = next(
486-
iter(status.applications[jenkins_with_proxy.name].units.values())
487-
)
488-
assert unit_status.address, "Invalid unit address"
489-
return unit_status.address
490-
except StopIteration as exc:
491-
raise StopIteration("Invalid unit status") from exc
478+
unit_ips = await get_model_unit_addresses(model=model, app_name=jenkins_with_proxy.name)
479+
assert unit_ips, f"Unit IP address not found for {jenkins_with_proxy.name}"
480+
return unit_ips[0]
492481

493482

494483
@pytest_asyncio.fixture(scope="module", name="proxy_jenkins_web_address")
@@ -781,10 +770,9 @@ async def traefik_application_fixture(model: Model):
781770
await model.wait_for_idle(
782771
status="active", apps=[traefik.name], timeout=20 * 60, idle_period=30, raise_on_error=False
783772
)
784-
status = await model.get_status(filters=[traefik.name])
785-
unit = next(iter(status.applications[traefik.name].units))
786-
traefik_address = status["applications"][traefik.name]["units"][unit]["address"]
787-
return (traefik, traefik_address)
773+
unit_ips = await get_model_unit_addresses(model=model, app_name=traefik.name)
774+
assert unit_ips, f"Unit IP address not found for {traefik.name}"
775+
return (traefik, unit_ips[0])
788776

789777

790778
@pytest_asyncio.fixture(scope="module", name="oathkeeper_related")

tests/integration/constants.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Constants for Jenkins-k8s-operator charm integration tests."""

tests/integration/dex.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""DEX deployment and utilities for testing."""

tests/integration/helpers.py

+18-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Helpers for Jenkins-k8s-operator charm integration tests."""
@@ -14,6 +14,7 @@
1414
import requests
1515
import tenacity
1616
from juju.application import Application
17+
from juju.client._definitions import ApplicationStatus, FullStatus, UnitStatus
1718
from juju.model import Model
1819
from juju.unit import Unit
1920
from pytest_operator.plugin import OpsTest
@@ -70,7 +71,7 @@ async def install_plugins(
7071
)
7172

7273

73-
async def get_model_jenkins_unit_address(model: Model, app_name: str):
74+
async def get_model_unit_addresses(model: Model, app_name: str) -> list[str]:
7475
"""Extract the address of a given unit.
7576
7677
Args:
@@ -80,10 +81,18 @@ async def get_model_jenkins_unit_address(model: Model, app_name: str):
8081
Returns:
8182
the IP address of the Jenkins unit.
8283
"""
83-
status = await model.get_status()
84-
unit = list(status.applications[app_name].units)[0]
85-
address = status["applications"][app_name]["units"][unit]["address"]
86-
return address
84+
status: FullStatus = await model.get_status()
85+
# mypy cannot infer the type ApplicationStatus but thinks its the base class type "Type".
86+
application_status: ApplicationStatus | None = status.applications[app_name] # type: ignore
87+
assert application_status, f"Application status {app_name} not found in {status}"
88+
# mypy cannot infer the type UnitStatus but thinks its the base class type "Type".
89+
unit_status_map: dict[typing.Any, UnitStatus | None] = application_status.units # type: ignore
90+
units_statuses: list[UnitStatus | None] = list(unit_status_map.values())
91+
return [
92+
str(unit_status.address)
93+
for unit_status in units_statuses
94+
if unit_status and unit_status.address
95+
]
8796

8897

8998
def gen_test_job_xml(node_label: str):
@@ -314,8 +323,9 @@ async def generate_unit_web_client_from_application(
314323
A Jenkins web client.
315324
"""
316325
assert model
317-
unit_ip = await get_model_jenkins_unit_address(model, jenkins_app.name)
318-
address = f"http://{unit_ip}:8080"
326+
unit_ips = await get_model_unit_addresses(model, jenkins_app.name)
327+
assert unit_ips, f"Unit IP address not found for {jenkins_app.name}"
328+
address = f"http://{unit_ips[0]}:8080"
319329
jenkins_unit = jenkins_app.units[0]
320330
jenkins_client = await generate_jenkins_client_from_application(ops_test, jenkins_app, address)
321331
unit_web_client = UnitWebClient(unit=jenkins_unit, web=address, client=jenkins_client)

tests/integration/pre_run_script.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/bin/bash
22

3-
# Copyright 2024 Canonical Ltd.
3+
# Copyright 2025 Canonical Ltd.
44
# See LICENSE file for licensing details.
55

66
# Pre-run script for integration test operator-workflows action.

tests/integration/substrings.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Helper functions for tests."""

tests/integration/test_auth_proxy.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Integration tests for jenkins-k8s-operator with auth_proxy."""

tests/integration/test_cos.py

+14-15
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Integration tests for jenkins-k8s-operator with COS."""
@@ -11,11 +11,10 @@
1111
import requests
1212
from juju.action import Action
1313
from juju.application import Application
14-
from juju.client._definitions import FullStatus
1514
from juju.model import Model
1615
from kubernetes.client import CoreV1Api
1716

18-
from .helpers import wait_for
17+
from .helpers import get_model_unit_addresses, wait_for
1918
from .types_ import UnitWebClient
2019

2120
logger = logging.getLogger(__name__)
@@ -36,11 +35,10 @@ async def test_prometheus_integration(
3635
assert res.status_code == 200
3736

3837
model: Model = unit_web_client.unit.model
39-
status: FullStatus = await model.get_status(filters=[prometheus_related.name])
40-
for unit in status.applications[prometheus_related.name].units.values():
41-
query_targets = requests.get(
42-
f"http://{unit.address}:9090/api/v1/targets", timeout=10
43-
).json()
38+
unit_ips = await get_model_unit_addresses(model=model, app_name=prometheus_related.name)
39+
assert unit_ips, f"Unit IP address not found for {prometheus_related.name}"
40+
for ip in unit_ips:
41+
query_targets = requests.get(f"http://{ip}:9090/api/v1/targets", timeout=10).json()
4442
assert len(query_targets["data"]["activeTargets"])
4543

4644

@@ -85,12 +83,13 @@ async def test_loki_integration(
8583
loki to scrape.
8684
"""
8785
model: Model = unit_web_client.unit.model
88-
status: FullStatus = await model.get_status(filters=[loki_related.name])
89-
for unit in status.applications[loki_related.name].units.values():
86+
unit_ips = await get_model_unit_addresses(model=model, app_name=loki_related.name)
87+
assert unit_ips, f"Unit IP address not found for {loki_related.name}"
88+
for ip in unit_ips:
9089
await wait_for(
9190
functools.partial(
9291
log_files_exist,
93-
unit.address,
92+
ip,
9493
application.name,
9594
("/var/lib/jenkins/logs/jenkins.log",),
9695
),
@@ -151,20 +150,20 @@ async def test_grafana_integration(
151150
assert: grafana Jenkins dashboard can be found
152151
"""
153152
model: Model = application.model
154-
status: FullStatus = await model.get_status(filters=[grafana_related.name])
155153
action: Action = await grafana_related.units[0].run_action("get-admin-password")
156154
await action.wait()
157155
password = action.results["admin-password"]
158-
for unit in status.applications[grafana_related.name].units.values():
156+
unit_ips = await get_model_unit_addresses(model=model, app_name=grafana_related.name)
157+
for ip in unit_ips:
159158
sess = requests.session()
160159
sess.post(
161-
f"http://{unit.address}:3000/login",
160+
f"http://{ip}:3000/login",
162161
json={
163162
"user": "admin",
164163
"password": password,
165164
},
166165
).raise_for_status()
167166
await wait_for(
168-
functools.partial(dashboard_exist, loggedin_session=sess, unit_address=unit.address),
167+
functools.partial(dashboard_exist, loggedin_session=sess, unit_address=ip),
169168
timeout=60 * 20,
170169
)

tests/integration/test_external_agent.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Integration tests for jenkins-k8s-operator with ingress."""

tests/integration/test_ingress.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Integration tests for jenkins-k8s-operator with ingress."""

tests/integration/test_jenkins.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Canonical Ltd.
1+
# Copyright 2025 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

44
"""Integration tests for jenkins-k8s-operator charm."""

0 commit comments

Comments
 (0)