Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove legacy slave integration #42

Merged
merged 1 commit into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/integration_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ jobs:
./tests/integration/pre_run_script.sh"
extra-arguments: |
--kube-config ${GITHUB_WORKSPACE}/kube-config
modules: '["test_agent_k8s.py", "test_agent_machine.py"]'
modules: '["test_agent_k8s.py"]'
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ by creating and accepting our cross-model relation. We do this from within the
k8s model:

```bash
juju offer jenkins-agent-k8s:slave
juju offer jenkins-agent-k8s:agent
# The output will be something like:
# Application "jenkins-agent" endpoints [slave] available at "admin/jenkins-agent-k8s.jenkins-agent"
# Application "jenkins-agent" endpoints [agent] available at "admin/jenkins-agent-k8s.jenkins-agent"
```

Switch back to your IaaS model where you deployed jenkins and run:
Expand Down
2 changes: 0 additions & 2 deletions metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,5 @@ resources:
type: oci-image
description: OCI image for Jenkins k8s agent
provides:
slave:
interface: jenkins-slave
agent:
interface: jenkins_agent_v0
108 changes: 1 addition & 107 deletions src/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import pebble
import server
from state import AGENT_RELATION, SLAVE_RELATION, State
from state import AGENT_RELATION, State

logger = logging.getLogger()

Expand All @@ -30,15 +30,6 @@ def __init__(self, charm: ops.CharmBase, state: State, pebble_service: pebble.Pe
self.state = state
self.pebble_service = pebble_service

charm.framework.observe(
charm.on[SLAVE_RELATION].relation_joined, self._on_slave_relation_joined
)
charm.framework.observe(
charm.on[SLAVE_RELATION].relation_changed, self._on_slave_relation_changed
)
charm.framework.observe(
charm.on[SLAVE_RELATION].relation_departed, self._on_slave_relation_departed
)
charm.framework.observe(
charm.on[AGENT_RELATION].relation_joined, self._on_agent_relation_joined
)
Expand All @@ -49,27 +40,6 @@ def __init__(self, charm: ops.CharmBase, state: State, pebble_service: pebble.Pe
charm.on[AGENT_RELATION].relation_departed, self._on_agent_relation_departed
)

def _on_slave_relation_joined(self, event: ops.RelationJoinedEvent) -> None:
"""Handle slave relation joined event.

Args:
event: The event fired when an agent has joined the "slave" relation.
"""
if self.state.jenkins_config:
logger.warning(
"Jenkins configuration already exists. Ignoring %s relation.", event.relation.name
)
return

logger.info("%s relation joined.", event.relation.name)
self.charm.unit.status = ops.MaintenanceStatus(
f"Setting up '{event.relation.name}' relation."
)

relation_data = self.state.agent_meta.get_jenkins_slave_interface_dict()
logger.debug("Slave relation data set: %s", relation_data)
event.relation.data[self.charm.unit].update(relation_data)

def _on_agent_relation_joined(self, event: ops.RelationJoinedEvent) -> None:
"""Handle agent relation joined event.

Expand All @@ -91,73 +61,6 @@ def _on_agent_relation_joined(self, event: ops.RelationJoinedEvent) -> None:
logger.debug("Agent relation data set: %s", relation_data)
event.relation.data[self.charm.unit].update(relation_data)

def _on_slave_relation_changed(self, event: ops.RelationChangedEvent) -> None:
"""Handle slave relation changed event.

Args:
event: The event fired when slave relation data has changed.

Raises:
AgentJarDownloadError: if the Jenkins agent failed to download.
"""
logger.info("%s relation changed.", event.relation.name)

if self.state.jenkins_config or self.state.agent_relation_credentials:
logger.warning(
"Jenkins configuration already exists. Ignoring %s relation.", event.relation.name
)
return

container = self.charm.unit.get_container(self.state.jenkins_agent_service_name)
if not container.can_connect():
logger.warning("Jenkins agent container not yet ready. Deferring.")
event.defer()
return

# Check if the pebble service has started and set agent ready.
if container.exists(str(server.AGENT_READY_PATH)):
logger.warning("Given agent already registered. Skipping.")
return

if not self.state.slave_relation_credentials:
self.charm.unit.status = ops.WaitingStatus("Waiting for complete relation data.")
logger.info("Waiting for complete relation data.")
# The event needs to be retried after the agent credentials have been set.
event.defer()
return

self.charm.unit.status = ops.MaintenanceStatus("Downloading Jenkins agent executable.")
try:
server.download_jenkins_agent(
server_url=self.state.slave_relation_credentials.address, container=container
)
except server.AgentJarDownloadError as exc:
logger.error("Failed to download Jenkins agent executable, %s", exc)
raise

self.charm.unit.status = ops.MaintenanceStatus("Validating credentials.")
if not server.validate_credentials(
agent_name=self.state.agent_meta.name,
credentials=self.state.slave_relation_credentials,
container=container,
add_random_delay=True,
):
# The jenkins server sets credentials one by one, if some other agent unit in the
# relation took this credential first, it the agent unit should wait for the next
# secret update and try grabbing that.
logger.warning(
"Failed credential for agent %s, will wait for next credentials to be set",
self.state.agent_meta.name,
)
self.charm.unit.status = ops.WaitingStatus("Waiting for credentials.")
return

self.start_agent_from_relation(
container=container,
credentials=self.state.slave_relation_credentials,
agent_name=self.state.agent_meta.name,
)

def _on_agent_relation_changed(self, event: ops.RelationChangedEvent) -> None:
"""Handle agent relation changed event.

Expand Down Expand Up @@ -227,15 +130,6 @@ def start_agent_from_relation(
)
self.charm.unit.status = ops.ActiveStatus()

def _on_slave_relation_departed(self, _: ops.RelationDepartedEvent) -> None:
"""Handle slave relation departed event."""
container = self.charm.unit.get_container(self.state.jenkins_agent_service_name)
if not container.can_connect():
logger.warning("Relation departed before service ready.")
return
self.pebble_service.stop_agent(container=container)
self.charm.unit.status = ops.BlockedStatus("Waiting for config/relation.")

def _on_agent_relation_departed(self, _: ops.RelationDepartedEvent) -> None:
"""Handle agent relation departed event."""
container = self.charm.unit.get_container(self.state.jenkins_agent_service_name)
Expand Down
14 changes: 2 additions & 12 deletions src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import agent
import pebble
import server
from state import AGENT_RELATION, SLAVE_RELATION, InvalidStateError, State
from state import AGENT_RELATION, InvalidStateError, State

logger = logging.getLogger()

Expand Down Expand Up @@ -62,21 +62,11 @@ def _register_via_config(
event.defer()
return

if (
not self.state.jenkins_config
and not self.model.get_relation(SLAVE_RELATION)
and not self.model.get_relation(AGENT_RELATION)
):
if not self.state.jenkins_config and not self.model.get_relation(AGENT_RELATION):
self.model.unit.status = ops.BlockedStatus("Waiting for config/relation.")
return

if not self.state.jenkins_config:
if self.model.get_relation(SLAVE_RELATION):
self.model.unit.status = ops.BlockedStatus(
"Please remove and re-relate slave relation."
)
return
# Support fallback relation to AGENT_RELATION.
self.model.unit.status = ops.BlockedStatus(
"Please remove and re-relate agent relation."
)
Expand Down
12 changes: 0 additions & 12 deletions src/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,6 @@ class Agent(BaseModel):
labels: str
name: str

def get_jenkins_slave_interface_dict(self) -> typing.Dict[str, str]:
"""Generate dictionary representation of agent metadata.

Returns:
A dictionary adhering to jenkins-slave interface.
"""
return {
"executors": str(self.num_executors),
"labels": self.labels,
"slavehost": self.name,
}

def get_jenkins_agent_v0_interface_dict(self) -> typing.Dict[str, str]:
"""Generate dictionary representation of agent metadata.

Expand Down
32 changes: 0 additions & 32 deletions src/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
import metadata
import server

# relation name used for compatibility with machine Jenkins server charm.
SLAVE_RELATION = "slave"
# agent relation name
AGENT_RELATION = "agent"

Expand Down Expand Up @@ -103,24 +101,6 @@ def _get_jenkins_unit(
return None


def _get_credentials_from_slave_relation(
server_unit_databag: ops.RelationDataContent,
) -> typing.Optional[server.Credentials]:
"""Import server metadata from databag in slave relation.

Args:
server_unit_databag: The relation databag content from slave relation.

Returns:
Metadata if complete values(url, secret) are set. None otherwise.
"""
address = server_unit_databag.get("url")
secret = server_unit_databag.get("secret")
if not address or not secret:
return None
return server.Credentials(address=address, secret=secret)


def _get_credentials_from_agent_relation(
server_unit_databag: ops.RelationDataContent, unit_name: str
) -> typing.Optional[server.Credentials]:
Expand All @@ -147,16 +127,13 @@ class State:
Attrs:
agent_meta: The Jenkins agent metadata to register on Jenkins server.
jenkins_config: Jenkins configuration value from juju config.
slave_relation_credentials: The full set of credentials from the slave relation. None if
partial data is set.
agent_relation_credentials: The full set of credentials from the agent relation. None if
partial data is set or the credentials do not belong to current agent.
jenkins_agent_service_name: The Jenkins agent workload container name.
"""

agent_meta: metadata.Agent
jenkins_config: typing.Optional[JenkinsConfig]
slave_relation_credentials: typing.Optional[server.Credentials]
agent_relation_credentials: typing.Optional[server.Credentials]
jenkins_agent_service_name: str = "jenkins-k8s-agent"

Expand Down Expand Up @@ -189,14 +166,6 @@ def from_charm(cls, charm: ops.CharmBase) -> "State":
logging.error("Invalid jenkins config values, %s", exc)
raise InvalidStateError("Invalid jenkins config values.") from exc

slave_relation = charm.model.get_relation(SLAVE_RELATION)
slave_relation_credentials: typing.Optional[server.Credentials] = None
if slave_relation and (
slave_relation_jenkins_unit := _get_jenkins_unit(slave_relation.units, charm.app.name)
):
slave_relation_credentials = _get_credentials_from_slave_relation(
slave_relation.data[slave_relation_jenkins_unit]
)
agent_relation = charm.model.get_relation(AGENT_RELATION)
agent_relation_credentials: typing.Optional[server.Credentials] = None
if agent_relation and (
Expand All @@ -209,6 +178,5 @@ def from_charm(cls, charm: ops.CharmBase) -> "State":
return cls(
agent_meta=agent_meta,
jenkins_config=jenkins_config,
slave_relation_credentials=slave_relation_credentials,
agent_relation_credentials=agent_relation_credentials,
)
6 changes: 3 additions & 3 deletions tests/integration/test_agent_k8s.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ def containers_ready() -> bool:
pod_status: kubernetes.client.V1PodStatus = kube_core_client.read_namespaced_pod_status(
name=pod_name, namespace=model.name
).status
container_statuses: list[
kubernetes.client.V1ContainerStatus
] = pod_status.container_statuses
container_statuses: list[kubernetes.client.V1ContainerStatus] = (
pod_status.container_statuses
)
return all(status.ready for status in container_statuses)

await wait_for(containers_ready, timeout=60 * 10)
Expand Down
45 changes: 0 additions & 45 deletions tests/integration/test_agent_machine.py

This file was deleted.

Loading
Loading