Charmed-Kubernetes/kubernetes-worker/reactive/kubernetes_node_base.py

133 lines
4.4 KiB
Python

import os
from subprocess import check_call
from charms.layer import snap
from charms.leadership import leader_get, leader_set
from charms.reactive import (
clear_flag,
data_changed,
hook,
set_flag,
set_state,
when,
when_not,
)
from charmhelpers.core import hookenv
from charmhelpers.core.host import is_container
from charmhelpers.core.sysctl import create as create_sysctl
from charms.layer.kubernetes_common import arch
@hook("upgrade-charm")
def upgrade_charm():
clear_flag("kubernetes.cni-plugins.installed")
@when_not("kubernetes.cni-plugins.installed")
def install_cni_plugins():
"""Unpack the cni-plugins resource"""
hookenv.status_set("maintenance", "Installing CNI plugins")
# Get the resource via resource_get
try:
resource_name = "cni-{}".format(arch())
archive = hookenv.resource_get(resource_name)
except Exception:
message = "Error fetching the cni resource."
hookenv.log(message)
return
if not archive:
hookenv.log("Missing cni resource.")
return
# Handle null resource publication, we check if filesize < 1mb
filesize = os.stat(archive).st_size
if filesize < 1000000:
hookenv.log("Incomplete cni resource.")
return
unpack_path = "/opt/cni/bin"
os.makedirs(unpack_path, exist_ok=True)
cmd = ["tar", "xfvz", archive, "-C", unpack_path]
hookenv.log(cmd)
check_call(cmd)
set_flag("kubernetes.cni-plugins.installed")
@when("kubernetes-node.snaps.installed")
@when("snap.refresh.set")
@when("leadership.is_leader")
def process_snapd_timer():
"""
Set the snapd refresh timer on the leader so all cluster members
(present and future) will refresh near the same time.
:return: None
"""
# Get the current snapd refresh timer; we know layer-snap has set this
# when the 'snap.refresh.set' flag is present.
timer = snap.get(snapname="core", key="refresh.timer").decode("utf-8").strip()
if not timer:
# The core snap timer is empty. This likely means a subordinate timer
# reset ours. Try to set it back to a previously leader-set value,
# falling back to config if needed. Luckily, this should only happen
# during subordinate install, so this should remain stable afterward.
timer = leader_get("snapd_refresh") or hookenv.config("snapd_refresh")
snap.set_refresh_timer(timer)
# Ensure we have the timer known by snapd (it may differ from config).
timer = snap.get(snapname="core", key="refresh.timer").decode("utf-8").strip()
# The first time through, data_changed will be true. Subsequent calls
# should only update leader data if something changed.
if data_changed("snapd_refresh", timer):
hookenv.log("setting leader snapd_refresh timer to: {}".format(timer))
leader_set({"snapd_refresh": timer})
@when("kubernetes-node.snaps.installed")
@when("snap.refresh.set")
@when("leadership.changed.snapd_refresh")
@when_not("leadership.is_leader")
def set_snapd_timer():
"""
Set the snapd refresh.timer on non-leader cluster members.
:return: None
"""
# NB: This method should only be run when 'snap.refresh.set' is present.
# Layer-snap will always set a core refresh.timer, which may not be the
# same as our leader. Gating with 'snap.refresh.set' ensures layer-snap
# has finished and we are free to set our config to the leader's timer.
timer = leader_get("snapd_refresh") or "" # None will error
hookenv.log("setting snapd_refresh timer to: {}".format(timer))
snap.set_refresh_timer(timer)
@when("config.changed.sysctl")
def write_sysctl():
"""
:return: None
"""
sysctl_settings = hookenv.config("sysctl")
if sysctl_settings and not is_container():
create_sysctl(
sysctl_settings,
"/etc/sysctl.d/50-kubernetes-charm.conf",
# Some keys in the config may not exist in /proc/sys/net/.
# For example, the conntrack module may not be loaded when
# using lxd drivers insteam of kvm. In these cases, we
# simply ignore the missing keys, rather than making time
# consuming calls out to the filesystem to check for their
# existence.
ignore=True,
)
@when("config.changed.labels")
def handle_labels_changed():
set_state("node.label-config-required")