Optimize access to the snap data
Access to each key took around 15 to 20ms, with more than 50 keys it adds up, This code path is often executed. Get all keys from snapd at once, and compare with values to set. Fix issue when unit is departing and private key is removed. Change-Id: I655a79ece3f09271532e0f41914141532474f2ac Signed-off-by: Guillaume Boutry <guillaume.boutry@canonical.com>
This commit is contained in:
parent
2c8e658693
commit
a9e24c4580
@ -21,6 +21,7 @@ This charm provide hypervisor services as part of an OpenStack deployment
|
||||
"""
|
||||
|
||||
import base64
|
||||
import functools
|
||||
import logging
|
||||
import os
|
||||
import secrets
|
||||
@ -121,10 +122,16 @@ class MTlsCertificatesHandler(sunbeam_rhandlers.TlsCertificatesHandler):
|
||||
if csr is None:
|
||||
return {}
|
||||
|
||||
main_key = self._private_keys.get("main")
|
||||
if main_key is None:
|
||||
# this can happen when the relation is removed
|
||||
# or unit is departing
|
||||
logger.debug("No main key found")
|
||||
return {}
|
||||
for cert in certs:
|
||||
if cert.csr == csr:
|
||||
return {
|
||||
"key": self._private_keys["main"],
|
||||
"key": main_key,
|
||||
"cert": cert.certificate,
|
||||
"ca_cert": cert.ca,
|
||||
"ca_with_intermediates": cert.ca
|
||||
@ -307,21 +314,21 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm):
|
||||
|
||||
def set_snap_data(self, snap_data: dict):
|
||||
"""Set snap data on local snap."""
|
||||
cache = snap.SnapCache()
|
||||
cache = self.get_snap_cache()
|
||||
hypervisor = cache["openstack-hypervisor"]
|
||||
new_settings = {}
|
||||
for k in sorted(snap_data.keys()):
|
||||
try:
|
||||
if snap_data[k] != hypervisor.get(k, typed=True):
|
||||
new_settings[k] = snap_data[k]
|
||||
except snap.SnapError:
|
||||
# Trying to retrieve an unset parameter results in a snapError
|
||||
# so assume the snap.SnapError means there is missing config
|
||||
# that needs setting.
|
||||
# Setting a value to None will unset the value from the snap,
|
||||
# which will fail if the value was never set.
|
||||
if snap_data[k] is not None:
|
||||
new_settings[k] = snap_data[k]
|
||||
old_settings = hypervisor.get(None, typed=True)
|
||||
for key, new_value in snap_data.items():
|
||||
group, subkey = key.split(".")
|
||||
if (
|
||||
old_value := old_settings.get(group, {}).get(subkey)
|
||||
) is not None:
|
||||
if old_value != new_value:
|
||||
new_settings[key] = new_value
|
||||
# Setting a value to None will unset the value from the snap,
|
||||
# which will fail if the value was never set.
|
||||
elif new_value is not None:
|
||||
new_settings[key] = new_value
|
||||
if new_settings:
|
||||
logger.debug(f"Applying new snap settings {new_settings}")
|
||||
hypervisor.set(new_settings, typed=True)
|
||||
@ -332,7 +339,7 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm):
|
||||
"""Install snap if it is not already present."""
|
||||
config = self.model.config.get
|
||||
try:
|
||||
cache = snap.SnapCache()
|
||||
cache = self.get_snap_cache()
|
||||
hypervisor = cache["openstack-hypervisor"]
|
||||
|
||||
if not hypervisor.present:
|
||||
@ -345,6 +352,11 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm):
|
||||
e.message,
|
||||
)
|
||||
|
||||
@functools.cache
|
||||
def get_snap_cache(self) -> snap.SnapCache:
|
||||
"""Return snap cache."""
|
||||
return snap.SnapCache()
|
||||
|
||||
def configure_unit(self, event) -> None:
|
||||
"""Run configuration on this unit."""
|
||||
self.check_leader_ready()
|
||||
|
@ -83,7 +83,7 @@ LIBAPI = 2
|
||||
|
||||
# Increment this PATCH version before using `charmcraft publish-lib` or reset
|
||||
# to 0 if you are raising the major API version
|
||||
LIBPATCH = 5
|
||||
LIBPATCH = 7
|
||||
|
||||
|
||||
# Regex to locate 7-bit C1 ANSI sequences
|
||||
@ -319,7 +319,10 @@ class Snap(object):
|
||||
Default is to return a string.
|
||||
"""
|
||||
if typed:
|
||||
config = json.loads(self._snap("get", ["-d", key]))
|
||||
args = ["-d"]
|
||||
if key:
|
||||
args.append(key)
|
||||
config = json.loads(self._snap("get", args))
|
||||
if key:
|
||||
return config.get(key)
|
||||
return config
|
||||
@ -584,13 +587,16 @@ class Snap(object):
|
||||
"Installing snap %s, revision %s, tracking %s", self._name, revision, channel
|
||||
)
|
||||
self._install(channel, cohort, revision)
|
||||
else:
|
||||
logger.info("The snap installation completed successfully")
|
||||
elif revision is None or revision != self._revision:
|
||||
# The snap is installed, but we are changing it (e.g., switching channels).
|
||||
logger.info(
|
||||
"Refreshing snap %s, revision %s, tracking %s", self._name, revision, channel
|
||||
)
|
||||
self._refresh(channel=channel, cohort=cohort, revision=revision, devmode=devmode)
|
||||
logger.info("The snap installation completed successfully")
|
||||
logger.info("The snap refresh completed successfully")
|
||||
else:
|
||||
logger.info("Refresh of snap %s was unnecessary", self._name)
|
||||
|
||||
self._update_snap_apps()
|
||||
self._state = state
|
||||
|
Loading…
x
Reference in New Issue
Block a user