Skip to content

Commit

Permalink
Constructor provides a path to alternate optional kubectl
Browse files Browse the repository at this point in the history
  • Loading branch information
addyess committed Feb 12, 2024
1 parent 5d96a5a commit 6e87026
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 12 deletions.
36 changes: 26 additions & 10 deletions ops/charms/node_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

import json
import logging
from subprocess import run
from os import PathLike
import time
from os import PathLike
from pathlib import Path
from subprocess import run
from typing import Union, List, Mapping, Optional, Protocol, Tuple

from ops import Model, Object, CharmMeta, StoredState
Expand Down Expand Up @@ -35,10 +36,16 @@ class NodeLabelError(Exception):

pass

def __init__(self, charm: Charm, kubeconfig_path: Union[PathLike, str]):
def __init__(
self,
charm: Charm,
kubeconfig_path: Union[PathLike, str],
kubectl: Optional[PathLike] = "/snap/bin/kubectl",
):
super().__init__(parent=charm, key="NodeBase")
self.kubeconfig_path = kubeconfig_path
self.charm = charm
self.kubeconfig_path = kubeconfig_path
self.kubectl_path = kubectl
self._stored.set_default(current_labels=dict())

@staticmethod
Expand All @@ -56,13 +63,22 @@ def _retried_call(
else:
raise LabelMaker.NodeLabelError(retry_msg)

def _kubectl(self, command: str) -> str:
if not Path(self.kubectl_path).exists():
retry_msg = "Failed to find kubectl. Will retry."
stdout, _ = self._retried_call(["which", "kubectl"], retry_msg)
self.kubectl_path = stdout.decode().strip()

base = "{0} --kubeconfig={1}".format(self.kubectl_path, self.kubeconfig_path)
return base + " " + command

def active_labels(self) -> Optional[Mapping[str, str]]:
"""
Returns all existing labels if the api server can fetch from the node,
otherwise returns None indicating the node cannot be relabeled.
"""
cmd = "kubectl --kubeconfig={0} get node {1} -o=jsonpath={{.metadata.labels}}"
cmd = cmd.format(self.kubeconfig_path, self.charm.get_node_name())
cmd = self._kubectl("get node {0} -o=jsonpath={{.metadata.labels}}")
cmd = cmd.format(self.charm.get_node_name())
retry_msg = "Failed to get labels. Will retry."
try:
label_json, _ = LabelMaker._retried_call(cmd.split(), retry_msg)
Expand All @@ -82,8 +98,8 @@ def set_label(self, label: str, value: str) -> None:
@param str value: Value to associate with the label
@raises LabelMaker.NodeLabelError: if the label cannot be added
"""
cmd = "kubectl --kubeconfig={0} label node {1} {2}={3} --overwrite"
cmd = cmd.format(self.kubeconfig_path, self.charm.get_node_name(), label, value)
cmd = self._kubectl("label node {0} {1}={2} --overwrite")
cmd = cmd.format(self.charm.get_node_name(), label, value)
retry_msg = "Failed to apply label {0}={1}. Will retry.".format(label, value)
LabelMaker._retried_call(cmd.split(), retry_msg)

Expand All @@ -94,8 +110,8 @@ def remove_label(self, label: str) -> None:
@param str label: Label name to remove
@raises LabelMaker.NodeLabelError: if the label cannot be removed
"""
cmd = "kubectl --kubeconfig={0} label node {1} {2}-"
cmd = cmd.format(self.kubeconfig_path, self.charm.get_node_name(), label)
cmd = self._kubectl("label node {0} {1}-")
cmd = cmd.format(self.charm.get_node_name(), label)
retry_msg = "Failed to remove label {0}. Will retry.".format(label)
LabelMaker._retried_call(cmd.split(), retry_msg)

Expand Down
4 changes: 2 additions & 2 deletions ops/tests/unit/test_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def test_active_labels_apply_layers_with_cloud(subprocess_run, harness):
[
mock.call(
[
"kubectl",
"/snap/bin/kubectl",
f"--kubeconfig={KUBE_CONFIG}",
"label",
"node",
Expand Down Expand Up @@ -123,7 +123,7 @@ def test_active_labels_apply_layers_from_config(subprocess_run, harness, caplog)
[
mock.call(
[
"kubectl",
"/snap/bin/kubectl",
f"--kubeconfig={KUBE_CONFIG}",
"label",
"node",
Expand Down

0 comments on commit 6e87026

Please sign in to comment.