-
Notifications
You must be signed in to change notification settings - Fork 0
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
By hashing the config values and files, only restart services on differences #31
base: main
Are you sure you want to change the base?
Conversation
config_files = set( | ||
map( | ||
api_opts.get, | ||
( | ||
"tls-cert-file", | ||
"tls-private-key-file", | ||
"kubelet-certificate-authority", | ||
"kubelet-client-certificate", | ||
"kubelet-client-key", | ||
"authentication-token-webhook-config-file", | ||
"service-account-signing-key-file", | ||
"service-account-key-file", | ||
"encryption-provider-config", | ||
"etcd-cafile", | ||
"etcd-keyfile", | ||
"etcd-certfile", | ||
"authorization-webhook-config-file", | ||
"requestheader-client-ca-file", | ||
"proxy-client-cert-file", | ||
"proxy-client-key-file", | ||
"client-ca-file", | ||
"audit-policy-file", | ||
"audit-webhook-config-file", | ||
), | ||
) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these keys point to config files that may have been overwritten during the reconcile period for the api server
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity, how do you know that you didn't miss one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know... that's what i'm SO afraid of. Missing one would be bad
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eaudetcobello do you have any ideas/opinions on how to not miss a file? I could "scan all the arguments looking for file like strings" but that sounds not great
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honestly, I think this could become unmanageable in the future and might come back to bite us. Looking at the API server options, there seem to be a few common patterns:
- Options with the
file
suffix - Options with the
config
suffix - Options that include
certificate
in the name - Options that include
key
in the name
It might be a good idea to check if an option has any of these indicators before trying to process the file. Here's an example: https://regex101.com/r/m5Gq9m/1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the full list of args that can be files are listed here:
https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/
Some with comments like:
File with
Path to
File containing
file used
And the hits just keep coming. The docs and arguments names aren't consistent. Maybe in the go code there's a list -- but with every k8s release -- more and more arguments may or may not be config files. Yes -- each config file will need to be ensured it gets added to the list and the regex could be a cool way, but there's no guarantee upstream k8s will follow it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually, there's another argument here which I expressly excluded because it's not a config file but a log file: audit-log-path
We do not want to watch for changes in this file b/c it's a log -- always changing means the api server reboots every time.
I think this list requires brain-power or some other comprehensive list of arguments which are absolutely treated as "read" by the api-server when restarted
config_files = set( | ||
map( | ||
controller_opts.get, | ||
( | ||
"root-ca-file", | ||
"kubeconfig", | ||
"authorization-kubeconfig", | ||
"authentication-kubeconfig", | ||
"service-account-private-key-file", | ||
"tls-cert-file", | ||
"tls-private-key-file", | ||
), | ||
) | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these keys point to config files that may have been overwritten during the reconcile period for the controller-manager
config_files = { | ||
kube_proxy_opts["config"], | ||
kubeconfig, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these are config files that may have been overwritten during the reconcile period for the kube-proxy service
def configure_kubernetes_service(service, base_args, extra_args_config): | ||
extra_args = parse_extra_args(extra_args_config) | ||
|
||
args = {} | ||
args.update(base_args) | ||
args.update(extra_args) | ||
|
||
# TODO: CIS arg handling??? | ||
# CIS benchmark action may inject kv config to pass failing tests. Merge | ||
# these after the func args as they should take precedence. | ||
# cis_args_key = "cis-" + service | ||
# cis_args = db.get(cis_args_key) or {} | ||
# args.update(cis_args) | ||
|
||
# Remove any args with 'None' values (all k8s args are 'k=v') and | ||
# construct an arg string for use by 'snap set'. | ||
args = {k: v for k, v in args.items() if v is not None} | ||
args = ['--%s="%s"' % arg for arg in args.items()] | ||
args = " ".join(args) | ||
|
||
cmd = ["snap", "set", service, f"args={args}"] | ||
check_call(cmd) | ||
service_restart(f"snap.{service}.daemon") | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is moved down the page...
b1dd359
to
fa9a3db
Compare
fa9a3db
to
5c7fe83
Compare
config_files = set( | ||
map( | ||
api_opts.get, | ||
( | ||
"tls-cert-file", | ||
"tls-private-key-file", | ||
"kubelet-certificate-authority", | ||
"kubelet-client-certificate", | ||
"kubelet-client-key", | ||
"authentication-token-webhook-config-file", | ||
"service-account-signing-key-file", | ||
"service-account-key-file", | ||
"encryption-provider-config", | ||
"etcd-cafile", | ||
"etcd-keyfile", | ||
"etcd-certfile", | ||
"authorization-webhook-config-file", | ||
"requestheader-client-ca-file", | ||
"proxy-client-cert-file", | ||
"proxy-client-key-file", | ||
"client-ca-file", | ||
"audit-policy-file", | ||
"audit-webhook-config-file", | ||
), | ||
) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honestly, I think this could become unmanageable in the future and might come back to bite us. Looking at the API server options, there seem to be a few common patterns:
- Options with the
file
suffix - Options with the
config
suffix - Options that include
certificate
in the name - Options that include
key
in the name
It might be a good idea to check if an option has any of these indicators before trying to process the file. Here's an example: https://regex101.com/r/m5Gq9m/1
log.debug("%s: Added config value %s", service.capitalize(), key) | ||
for key in removed: | ||
log.debug("%s: Dropped config value %s", service.capitalize(), key) | ||
for key in modified: | ||
log.debug("%s: Updated config value %s", service.capitalize(), key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
log.debug("%s: Added config value %s", service.capitalize(), key) | |
for key in removed: | |
log.debug("%s: Dropped config value %s", service.capitalize(), key) | |
for key in modified: | |
log.debug("%s: Updated config value %s", service.capitalize(), key) | |
log.debug("%s: Added config value %s", service.capitalize(), key) | |
for key in removed: | |
log.debug("%s: Dropped config value %s", service.capitalize(), key) | |
for key in modified: | |
log.debug("%s: Updated config value %s", service.capitalize(), key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mateoflorido I think you'll like this. We can use this env var to control from the charm whether or not we want to use this caching feature.
def _enable_config_hashing() -> bool: | ||
"""This is a debug option to enable config hashing.""" | ||
env = os.environ.get("JUJU_FEATURE_KUBERNETES_SNAP_CONFIG_HASHING") or "" | ||
return env.lower() == "on" | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This allows the charm at runtime (per hook even!!!) decide whether or not it wants to enable hashing.
Now an upgrade action could restart the service even if there aren't any config changes. We could even expose via charm config (though i think that'd be going too far).
if not _enable_config_hashing(): | ||
log.debug("Config hashing disabled, skipping config change detection") | ||
yield True | ||
args_hash.unlink(missing_ok=True) | ||
return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if hashing isn't enabled, this method declares there are changes, and we should reconfigure the service (as before this feature existed) and it also clears the cache file if one exists.
Overview
Details
_snap_common_path(service) / "args-hash.txt"