mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 19:31:44 +00:00
Merge pull request #65719 from Cynerva/gkk/upgrade-resources
Automatic merge from submit-queue (batch tested with PRs 65719, 65764). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. juju: Fix upgrade actions not working with resources **What this PR does / why we need it**: This fixes an issue with the kubernetes-master and kubernetes-worker charms, where running the `upgrade` action does not actually perform an upgrade when snaps are attached as resources. **Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*: https://github.com/juju-solutions/bundle-canonical-kubernetes/issues/528 **Special notes for your reviewer**: The underlying issue is that both layer-snap and the kubernetes layers are using `any_file_changed` to look for changes in the resources. This PR fixes it by removing the use of `any_file_changed` in the top-level layers, and implementing our own code for it instead. **Release note**: ```release-note NONE ```
This commit is contained in:
commit
d62c08e75f
@ -15,6 +15,7 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
import hashlib
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import random
|
import random
|
||||||
@ -64,8 +65,11 @@ from charmhelpers.contrib.charmsupport import nrpe
|
|||||||
nrpe.Check.shortname_re = '[\.A-Za-z0-9-_]+$'
|
nrpe.Check.shortname_re = '[\.A-Za-z0-9-_]+$'
|
||||||
|
|
||||||
gcp_creds_env_key = 'GOOGLE_APPLICATION_CREDENTIALS'
|
gcp_creds_env_key = 'GOOGLE_APPLICATION_CREDENTIALS'
|
||||||
|
snap_resources = ['kubectl', 'kube-apiserver', 'kube-controller-manager',
|
||||||
|
'kube-scheduler', 'cdk-addons']
|
||||||
|
|
||||||
os.environ['PATH'] += os.pathsep + os.path.join(os.sep, 'snap', 'bin')
|
os.environ['PATH'] += os.pathsep + os.path.join(os.sep, 'snap', 'bin')
|
||||||
|
db = unitdata.kv()
|
||||||
|
|
||||||
|
|
||||||
def set_upgrade_needed(forced=False):
|
def set_upgrade_needed(forced=False):
|
||||||
@ -86,7 +90,6 @@ def channel_changed():
|
|||||||
|
|
||||||
def service_cidr():
|
def service_cidr():
|
||||||
''' Return the charm's service-cidr config '''
|
''' Return the charm's service-cidr config '''
|
||||||
db = unitdata.kv()
|
|
||||||
frozen_cidr = db.get('kubernetes-master.service-cidr')
|
frozen_cidr = db.get('kubernetes-master.service-cidr')
|
||||||
return frozen_cidr or hookenv.config('service-cidr')
|
return frozen_cidr or hookenv.config('service-cidr')
|
||||||
|
|
||||||
@ -94,7 +97,6 @@ def service_cidr():
|
|||||||
def freeze_service_cidr():
|
def freeze_service_cidr():
|
||||||
''' Freeze the service CIDR. Once the apiserver has started, we can no
|
''' Freeze the service CIDR. Once the apiserver has started, we can no
|
||||||
longer safely change this value. '''
|
longer safely change this value. '''
|
||||||
db = unitdata.kv()
|
|
||||||
db.set('kubernetes-master.service-cidr', service_cidr())
|
db.set('kubernetes-master.service-cidr', service_cidr())
|
||||||
|
|
||||||
|
|
||||||
@ -107,10 +109,8 @@ def check_for_upgrade_needed():
|
|||||||
add_rbac_roles()
|
add_rbac_roles()
|
||||||
set_state('reconfigure.authentication.setup')
|
set_state('reconfigure.authentication.setup')
|
||||||
remove_state('authentication.setup')
|
remove_state('authentication.setup')
|
||||||
changed = snap_resources_changed()
|
|
||||||
if changed == 'yes':
|
if not db.get('snap.resources.fingerprint.initialised'):
|
||||||
set_upgrade_needed()
|
|
||||||
elif changed == 'unknown':
|
|
||||||
# We are here on an upgrade from non-rolling master
|
# We are here on an upgrade from non-rolling master
|
||||||
# Since this upgrade might also include resource updates eg
|
# Since this upgrade might also include resource updates eg
|
||||||
# juju upgrade-charm kubernetes-master --resource kube-any=my.snap
|
# juju upgrade-charm kubernetes-master --resource kube-any=my.snap
|
||||||
@ -118,6 +118,9 @@ def check_for_upgrade_needed():
|
|||||||
# Forcibly means we do not prompt the user to call the upgrade action.
|
# Forcibly means we do not prompt the user to call the upgrade action.
|
||||||
set_upgrade_needed(forced=True)
|
set_upgrade_needed(forced=True)
|
||||||
|
|
||||||
|
migrate_resource_checksums()
|
||||||
|
check_resources_for_upgrade_needed()
|
||||||
|
|
||||||
# Set the auto storage backend to etcd2.
|
# Set the auto storage backend to etcd2.
|
||||||
auto_storage_backend = leader_get('auto_storage_backend')
|
auto_storage_backend = leader_get('auto_storage_backend')
|
||||||
is_leader = is_state('leadership.is_leader')
|
is_leader = is_state('leadership.is_leader')
|
||||||
@ -125,27 +128,56 @@ def check_for_upgrade_needed():
|
|||||||
leader_set(auto_storage_backend='etcd2')
|
leader_set(auto_storage_backend='etcd2')
|
||||||
|
|
||||||
|
|
||||||
def snap_resources_changed():
|
def get_resource_checksum_db_key(resource):
|
||||||
'''
|
''' Convert a resource name to a resource checksum database key. '''
|
||||||
Check if the snapped resources have changed. The first time this method is
|
return 'kubernetes-master.resource-checksums.' + resource
|
||||||
called will report "unknown".
|
|
||||||
|
|
||||||
Returns: "yes" in case a snap resource file has changed,
|
|
||||||
"no" in case a snap resources are the same as last call,
|
|
||||||
"unknown" if it is the first time this method is called
|
|
||||||
|
|
||||||
'''
|
def calculate_resource_checksum(resource):
|
||||||
db = unitdata.kv()
|
''' Calculate a checksum for a resource '''
|
||||||
resources = ['kubectl', 'kube-apiserver', 'kube-controller-manager',
|
md5 = hashlib.md5()
|
||||||
'kube-scheduler', 'cdk-addons']
|
path = hookenv.resource_get(resource)
|
||||||
paths = [hookenv.resource_get(resource) for resource in resources]
|
if path:
|
||||||
if db.get('snap.resources.fingerprint.initialised'):
|
with open(path, 'rb') as f:
|
||||||
result = 'yes' if any_file_changed(paths) else 'no'
|
data = f.read()
|
||||||
return result
|
md5.update(data)
|
||||||
else:
|
return md5.hexdigest()
|
||||||
db.set('snap.resources.fingerprint.initialised', True)
|
|
||||||
any_file_changed(paths)
|
|
||||||
return 'unknown'
|
def migrate_resource_checksums():
|
||||||
|
''' Migrate resource checksums from the old schema to the new one '''
|
||||||
|
for resource in snap_resources:
|
||||||
|
new_key = get_resource_checksum_db_key(resource)
|
||||||
|
if not db.get(new_key):
|
||||||
|
path = hookenv.resource_get(resource)
|
||||||
|
if path:
|
||||||
|
# old key from charms.reactive.helpers.any_file_changed
|
||||||
|
old_key = 'reactive.files_changed.' + path
|
||||||
|
old_checksum = db.get(old_key)
|
||||||
|
db.set(new_key, old_checksum)
|
||||||
|
else:
|
||||||
|
# No resource is attached. Previously, this meant no checksum
|
||||||
|
# would be calculated and stored. But now we calculate it as if
|
||||||
|
# it is a 0-byte resource, so let's go ahead and do that.
|
||||||
|
zero_checksum = hashlib.md5().hexdigest()
|
||||||
|
db.set(new_key, zero_checksum)
|
||||||
|
|
||||||
|
|
||||||
|
def check_resources_for_upgrade_needed():
|
||||||
|
hookenv.status_set('maintenance', 'Checking resources')
|
||||||
|
for resource in snap_resources:
|
||||||
|
key = get_resource_checksum_db_key(resource)
|
||||||
|
old_checksum = db.get(key)
|
||||||
|
new_checksum = calculate_resource_checksum(resource)
|
||||||
|
if new_checksum != old_checksum:
|
||||||
|
set_upgrade_needed()
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_and_store_resource_checksums():
|
||||||
|
for resource in snap_resources:
|
||||||
|
key = get_resource_checksum_db_key(resource)
|
||||||
|
checksum = calculate_resource_checksum(resource)
|
||||||
|
db.set(key, checksum)
|
||||||
|
|
||||||
|
|
||||||
def add_rbac_roles():
|
def add_rbac_roles():
|
||||||
@ -253,7 +285,8 @@ def install_snaps():
|
|||||||
snap.install('kube-scheduler', channel=channel)
|
snap.install('kube-scheduler', channel=channel)
|
||||||
hookenv.status_set('maintenance', 'Installing cdk-addons snap')
|
hookenv.status_set('maintenance', 'Installing cdk-addons snap')
|
||||||
snap.install('cdk-addons', channel=channel)
|
snap.install('cdk-addons', channel=channel)
|
||||||
snap_resources_changed()
|
calculate_and_store_resource_checksums()
|
||||||
|
db.set('snap.resources.fingerprint.initialised', True)
|
||||||
set_state('kubernetes-master.snaps.installed')
|
set_state('kubernetes-master.snaps.installed')
|
||||||
remove_state('kubernetes-master.components.started')
|
remove_state('kubernetes-master.components.started')
|
||||||
|
|
||||||
@ -1123,8 +1156,6 @@ def parse_extra_args(config_key):
|
|||||||
|
|
||||||
|
|
||||||
def configure_kubernetes_service(service, base_args, extra_args_key):
|
def configure_kubernetes_service(service, base_args, extra_args_key):
|
||||||
db = unitdata.kv()
|
|
||||||
|
|
||||||
prev_args_key = 'kubernetes-master.prev_args.' + service
|
prev_args_key = 'kubernetes-master.prev_args.' + service
|
||||||
prev_args = db.get(prev_args_key) or {}
|
prev_args = db.get(prev_args_key) or {}
|
||||||
|
|
||||||
@ -1412,7 +1443,6 @@ def set_token(password, save_salt):
|
|||||||
|
|
||||||
param: password - the password to be stored
|
param: password - the password to be stored
|
||||||
param: save_salt - the key to store the value of the token.'''
|
param: save_salt - the key to store the value of the token.'''
|
||||||
db = unitdata.kv()
|
|
||||||
db.set(save_salt, password)
|
db.set(save_salt, password)
|
||||||
return db.get(save_salt)
|
return db.get(save_salt)
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
@ -36,7 +37,7 @@ from charms.reactive import when, when_any, when_not, when_none
|
|||||||
|
|
||||||
from charms.kubernetes.common import get_version
|
from charms.kubernetes.common import get_version
|
||||||
|
|
||||||
from charms.reactive.helpers import data_changed, any_file_changed
|
from charms.reactive.helpers import data_changed
|
||||||
from charms.templating.jinja2 import render
|
from charms.templating.jinja2 import render
|
||||||
|
|
||||||
from charmhelpers.core import hookenv, unitdata
|
from charmhelpers.core import hookenv, unitdata
|
||||||
@ -52,6 +53,7 @@ kubeconfig_path = '/root/cdk/kubeconfig'
|
|||||||
kubeproxyconfig_path = '/root/cdk/kubeproxyconfig'
|
kubeproxyconfig_path = '/root/cdk/kubeproxyconfig'
|
||||||
kubeclientconfig_path = '/root/.kube/config'
|
kubeclientconfig_path = '/root/.kube/config'
|
||||||
gcp_creds_env_key = 'GOOGLE_APPLICATION_CREDENTIALS'
|
gcp_creds_env_key = 'GOOGLE_APPLICATION_CREDENTIALS'
|
||||||
|
snap_resources = ['kubectl', 'kubelet', 'kube-proxy']
|
||||||
|
|
||||||
os.environ['PATH'] += os.pathsep + os.path.join(os.sep, 'snap', 'bin')
|
os.environ['PATH'] += os.pathsep + os.path.join(os.sep, 'snap', 'bin')
|
||||||
db = unitdata.kv()
|
db = unitdata.kv()
|
||||||
@ -64,6 +66,7 @@ def upgrade_charm():
|
|||||||
hookenv.atexit(remove_state, 'config.changed.install_from_upstream')
|
hookenv.atexit(remove_state, 'config.changed.install_from_upstream')
|
||||||
|
|
||||||
cleanup_pre_snap_services()
|
cleanup_pre_snap_services()
|
||||||
|
migrate_resource_checksums()
|
||||||
check_resources_for_upgrade_needed()
|
check_resources_for_upgrade_needed()
|
||||||
|
|
||||||
# Remove the RC for nginx ingress if it exists
|
# Remove the RC for nginx ingress if it exists
|
||||||
@ -88,12 +91,56 @@ def upgrade_charm():
|
|||||||
set_state('kubernetes-worker.restart-needed')
|
set_state('kubernetes-worker.restart-needed')
|
||||||
|
|
||||||
|
|
||||||
|
def get_resource_checksum_db_key(resource):
|
||||||
|
''' Convert a resource name to a resource checksum database key. '''
|
||||||
|
return 'kubernetes-worker.resource-checksums.' + resource
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_resource_checksum(resource):
|
||||||
|
''' Calculate a checksum for a resource '''
|
||||||
|
md5 = hashlib.md5()
|
||||||
|
path = hookenv.resource_get(resource)
|
||||||
|
if path:
|
||||||
|
with open(path, 'rb') as f:
|
||||||
|
data = f.read()
|
||||||
|
md5.update(data)
|
||||||
|
return md5.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_resource_checksums():
|
||||||
|
''' Migrate resource checksums from the old schema to the new one '''
|
||||||
|
for resource in snap_resources:
|
||||||
|
new_key = get_resource_checksum_db_key(resource)
|
||||||
|
if not db.get(new_key):
|
||||||
|
path = hookenv.resource_get(resource)
|
||||||
|
if path:
|
||||||
|
# old key from charms.reactive.helpers.any_file_changed
|
||||||
|
old_key = 'reactive.files_changed.' + path
|
||||||
|
old_checksum = db.get(old_key)
|
||||||
|
db.set(new_key, old_checksum)
|
||||||
|
else:
|
||||||
|
# No resource is attached. Previously, this meant no checksum
|
||||||
|
# would be calculated and stored. But now we calculate it as if
|
||||||
|
# it is a 0-byte resource, so let's go ahead and do that.
|
||||||
|
zero_checksum = hashlib.md5().hexdigest()
|
||||||
|
db.set(new_key, zero_checksum)
|
||||||
|
|
||||||
|
|
||||||
def check_resources_for_upgrade_needed():
|
def check_resources_for_upgrade_needed():
|
||||||
hookenv.status_set('maintenance', 'Checking resources')
|
hookenv.status_set('maintenance', 'Checking resources')
|
||||||
resources = ['kubectl', 'kubelet', 'kube-proxy']
|
for resource in snap_resources:
|
||||||
paths = [hookenv.resource_get(resource) for resource in resources]
|
key = get_resource_checksum_db_key(resource)
|
||||||
if any_file_changed(paths):
|
old_checksum = db.get(key)
|
||||||
set_upgrade_needed()
|
new_checksum = calculate_resource_checksum(resource)
|
||||||
|
if new_checksum != old_checksum:
|
||||||
|
set_upgrade_needed()
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_and_store_resource_checksums():
|
||||||
|
for resource in snap_resources:
|
||||||
|
key = get_resource_checksum_db_key(resource)
|
||||||
|
checksum = calculate_resource_checksum(resource)
|
||||||
|
db.set(key, checksum)
|
||||||
|
|
||||||
|
|
||||||
def set_upgrade_needed():
|
def set_upgrade_needed():
|
||||||
@ -151,7 +198,6 @@ def upgrade_needed_status():
|
|||||||
|
|
||||||
@when('kubernetes-worker.snaps.upgrade-specified')
|
@when('kubernetes-worker.snaps.upgrade-specified')
|
||||||
def install_snaps():
|
def install_snaps():
|
||||||
check_resources_for_upgrade_needed()
|
|
||||||
channel = hookenv.config('channel')
|
channel = hookenv.config('channel')
|
||||||
hookenv.status_set('maintenance', 'Installing kubectl snap')
|
hookenv.status_set('maintenance', 'Installing kubectl snap')
|
||||||
snap.install('kubectl', channel=channel, classic=True)
|
snap.install('kubectl', channel=channel, classic=True)
|
||||||
@ -159,6 +205,7 @@ def install_snaps():
|
|||||||
snap.install('kubelet', channel=channel, classic=True)
|
snap.install('kubelet', channel=channel, classic=True)
|
||||||
hookenv.status_set('maintenance', 'Installing kube-proxy snap')
|
hookenv.status_set('maintenance', 'Installing kube-proxy snap')
|
||||||
snap.install('kube-proxy', channel=channel, classic=True)
|
snap.install('kube-proxy', channel=channel, classic=True)
|
||||||
|
calculate_and_store_resource_checksums()
|
||||||
set_state('kubernetes-worker.snaps.installed')
|
set_state('kubernetes-worker.snaps.installed')
|
||||||
set_state('kubernetes-worker.restart-needed')
|
set_state('kubernetes-worker.restart-needed')
|
||||||
remove_state('kubernetes-worker.snaps.upgrade-needed')
|
remove_state('kubernetes-worker.snaps.upgrade-needed')
|
||||||
|
Loading…
Reference in New Issue
Block a user