vendor updates

This commit is contained in:
Serguei Bezverkhi
2018-03-06 17:33:18 -05:00
parent 4b3ebc171b
commit e9033989a0
5854 changed files with 248382 additions and 119809 deletions

View File

@ -60,7 +60,7 @@ def main():
if not validate_space(context['RBD_SIZE']):
return
# Ensure our paramters match
# Ensure our parameters match
param_validation = validate_parameters(context['RBD_NAME'],
context['RBD_FS'],
context['PV_MODE'])

View File

@ -3,6 +3,10 @@ options:
type: boolean
default: True
description: Deploy the Kubernetes Dashboard and Heapster addons
enable-kube-dns:
type: boolean
default: True
description: Deploy kube-dns addon
dns_domain:
type: string
default: cluster.local
@ -29,7 +33,7 @@ options:
detected on a worker node.
channel:
type: string
default: "1.8/stable"
default: "1.9/stable"
description: |
Snap channel to install Kubernetes master services from
client_password:
@ -76,3 +80,9 @@ options:
description: |
When true, master nodes will not be upgraded until the user triggers
it manually by running the upgrade action.
storage-backend:
type: string
default: "auto"
description: |
The storage backend for kube-apiserver persistence. Can be "etcd2", "etcd3", or
"auto". Auto mode will select etcd3 on new installations, or etcd2 on upgrades.

View File

@ -24,7 +24,7 @@ import string
import json
import ipaddress
import charms.leadership
from charms.leadership import leader_get, leader_set
from shutil import move
@ -39,7 +39,7 @@ from charms.reactive import hook
from charms.reactive import remove_state
from charms.reactive import set_state
from charms.reactive import is_state
from charms.reactive import when, when_any, when_not, when_all
from charms.reactive import when, when_any, when_not
from charms.reactive.helpers import data_changed, any_file_changed
from charms.kubernetes.common import get_version
from charms.kubernetes.common import retry
@ -63,13 +63,13 @@ nrpe.Check.shortname_re = '[\.A-Za-z0-9-_]+$'
os.environ['PATH'] += os.pathsep + os.path.join(os.sep, 'snap', 'bin')
def set_upgrade_needed():
def set_upgrade_needed(forced=False):
set_state('kubernetes-master.upgrade-needed')
config = hookenv.config()
previous_channel = config.previous('channel')
require_manual = config.get('require-manual-upgrade')
hookenv.log('set upgrade needed')
if previous_channel is None or not require_manual:
if previous_channel is None or not require_manual or forced:
hookenv.log('forcing upgrade')
set_state('kubernetes-master.upgrade-specified')
@ -102,12 +102,45 @@ def check_for_upgrade_needed():
add_rbac_roles()
set_state('reconfigure.authentication.setup')
remove_state('authentication.setup')
changed = snap_resources_changed()
if changed == 'yes':
set_upgrade_needed()
elif changed == 'unknown':
# We are here on an upgrade from non-rolling master
# Since this upgrade might also include resource updates eg
# juju upgrade-charm kubernetes-master --resource kube-any=my.snap
# we take no risk and forcibly upgrade the snaps.
# Forcibly means we do not prompt the user to call the upgrade action.
set_upgrade_needed(forced=True)
# Set the auto storage backend to etcd2.
auto_storage_backend = leader_get('auto_storage_backend')
is_leader = is_state('leadership.is_leader')
if not auto_storage_backend and is_leader:
leader_set(auto_storage_backend='etcd2')
def snap_resources_changed():
'''
Check if the snapped resources have changed. The first time this method is
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
'''
db = unitdata.kv()
resources = ['kubectl', 'kube-apiserver', 'kube-controller-manager',
'kube-scheduler', 'cdk-addons']
paths = [hookenv.resource_get(resource) for resource in resources]
if any_file_changed(paths):
set_upgrade_needed()
if db.get('snap.resources.fingerprint.initialised'):
result = 'yes' if any_file_changed(paths) else 'no'
return result
else:
db.set('snap.resources.fingerprint.initialised', True)
any_file_changed(paths)
return 'unknown'
def add_rbac_roles():
@ -222,6 +255,7 @@ def install_snaps():
snap.install('kube-scheduler', channel=channel)
hookenv.status_set('maintenance', 'Installing cdk-addons snap')
snap.install('cdk-addons', channel=channel)
snap_resources_changed()
set_state('kubernetes-master.snaps.installed')
remove_state('kubernetes-master.components.started')
@ -236,12 +270,17 @@ def password_changed():
elif password == "":
# Password not initialised
password = token_generator()
setup_basic_auth(password, "admin", "admin")
setup_basic_auth(password, "admin", "admin", "system:masters")
set_state('reconfigure.authentication.setup')
remove_state('authentication.setup')
set_state('client.password.initialised')
@when('config.changed.storage-backend')
def storage_backend_changed():
remove_state('kubernetes-master.components.started')
@when('cni.connected')
@when_not('cni.configured')
def configure_cni(cni):
@ -288,7 +327,7 @@ def setup_leader_authentication():
# path as a key.
# eg:
# {'/root/cdk/serviceaccount.key': 'RSA:2471731...'}
charms.leadership.leader_set(leader_data)
leader_set(leader_data)
remove_state('kubernetes-master.components.started')
set_state('authentication.setup')
@ -336,7 +375,7 @@ def get_keys_from_leader(keys, overwrite_local=False):
# If the path does not exist, assume we need it
if not os.path.exists(k) or overwrite_local:
# Fetch data from leadership broadcast
contents = charms.leadership.leader_get(k)
contents = leader_get(k)
# Default to logging the warning and wait for leader data to be set
if contents is None:
msg = "Waiting on leaders crypto keys."
@ -360,6 +399,7 @@ def set_app_version():
@when('cdk-addons.configured', 'kube-api-endpoint.available',
'kube-control.connected')
@when_not('kubernetes-master.upgrade-needed')
def idle_status(kube_api, kube_control):
''' Signal at the end of the run that we are running. '''
if not all_kube_system_pods_running():
@ -394,6 +434,7 @@ def master_services_down():
@when('etcd.available', 'tls_client.server.certificate.saved',
'authentication.setup')
@when('leadership.set.auto_storage_backend')
@when_not('kubernetes-master.components.started')
def start_master(etcd):
'''Run the Kubernetes master components.'''
@ -411,10 +452,10 @@ def start_master(etcd):
handle_etcd_relation(etcd)
# Add CLI options to all components
configure_apiserver(etcd)
configure_apiserver(etcd.get_connection_string(), getStorageBackend())
configure_controller_manager()
configure_scheduler()
set_state('kubernetes-master.components.started')
hookenv.open_port(6443)
@ -422,7 +463,7 @@ def start_master(etcd):
def etcd_data_change(etcd):
''' Etcd scale events block master reconfiguration due to the
kubernetes-master.components.started state. We need a way to
handle these events consistenly only when the number of etcd
handle these events consistently only when the number of etcd
units has actually changed '''
# key off of the connection string
@ -433,15 +474,31 @@ def etcd_data_change(etcd):
if data_changed('etcd-connect', connection_string):
remove_state('kubernetes-master.components.started')
# We are the leader and the auto_storage_backend is not set meaning
# this is the first time we connect to etcd.
auto_storage_backend = leader_get('auto_storage_backend')
is_leader = is_state('leadership.is_leader')
if is_leader and not auto_storage_backend:
if etcd.get_version().startswith('3.'):
leader_set(auto_storage_backend='etcd3')
else:
leader_set(auto_storage_backend='etcd2')
@when('kube-control.connected')
@when('cdk-addons.configured')
def send_cluster_dns_detail(kube_control):
''' Send cluster DNS info '''
# Note that the DNS server doesn't necessarily exist at this point. We know
# where we're going to put it, though, so let's send the info anyway.
dns_ip = get_dns_ip()
kube_control.set_dns(53, hookenv.config('dns_domain'), dns_ip)
enableKubeDNS = hookenv.config('enable-kube-dns')
dnsDomain = hookenv.config('dns_domain')
dns_ip = None
if enableKubeDNS:
try:
dns_ip = get_dns_ip()
except CalledProcessError:
hookenv.log("kubedns not ready yet")
return
kube_control.set_dns(53, dnsDomain, dns_ip, enableKubeDNS)
@when('kube-control.connected')
@ -502,8 +559,23 @@ def push_service_data(kube_api):
kube_api.configure(port=6443)
@when('certificates.available')
def send_data(tls):
def get_ingress_address(relation):
try:
network_info = hookenv.network_get(relation.relation_name)
except NotImplementedError:
network_info = []
if network_info and 'ingress-addresses' in network_info:
# just grab the first one for now, maybe be more robust here?
return network_info['ingress-addresses'][0]
else:
# if they don't have ingress-addresses they are running a juju that
# doesn't support spaces, so just return the private address
return hookenv.unit_get('private-address')
@when('certificates.available', 'kube-api-endpoint.available')
def send_data(tls, kube_api_endpoint):
'''Send the data that is required to create a server certificate for
this server.'''
# Use the public ip of this unit as the Common Name for the certificate.
@ -512,11 +584,14 @@ def send_data(tls):
# Get the SDN gateway based on the cidr address.
kubernetes_service_ip = get_kubernetes_service_ip()
# Get ingress address
ingress_ip = get_ingress_address(kube_api_endpoint)
domain = hookenv.config('dns_domain')
# Create SANs that the tls layer will add to the server cert.
sans = [
hookenv.unit_public_ip(),
hookenv.unit_private_ip(),
ingress_ip,
socket.gethostname(),
kubernetes_service_ip,
'kubernetes',
@ -537,12 +612,13 @@ def send_data(tls):
tls.request_server_cert(common_name, sans, certificate_name)
@when('config.changed.extra_sans', 'certificates.available')
def update_certificate(tls):
@when('config.changed.extra_sans', 'certificates.available',
'kube-api-endpoint.available')
def update_certificate(tls, kube_api_endpoint):
# Using the config.changed.extra_sans flag to catch changes.
# IP changes will take ~5 minutes or so to propagate, but
# it will update.
send_data(tls)
send_data(tls, kube_api_endpoint)
@when('certificates.server.cert.available',
@ -554,7 +630,7 @@ def kick_api_server(tls):
if data_changed('cert', tls.get_server_cert()):
# certificate changed, so restart the api server
hookenv.log("Certificate information changed, restarting api server")
set_state('kube-apiserver.do-restart')
restart_apiserver()
tls_client.reset_certificate_write_flag('server')
@ -563,11 +639,13 @@ def configure_cdk_addons():
''' Configure CDK addons '''
remove_state('cdk-addons.configured')
dbEnabled = str(hookenv.config('enable-dashboard-addons')).lower()
dnsEnabled = str(hookenv.config('enable-kube-dns')).lower()
args = [
'arch=' + arch(),
'dns-ip=' + get_dns_ip(),
'dns-ip=' + get_deprecated_dns_ip(),
'dns-domain=' + hookenv.config('dns_domain'),
'enable-dashboard=' + dbEnabled
'enable-dashboard=' + dbEnabled,
'enable-kube-dns=' + dnsEnabled
]
check_call(['snap', 'set', 'cdk-addons'] + args)
if not addons_ready():
@ -691,7 +769,7 @@ def ceph_storage(ceph_admin):
cmd = ['kubectl', 'apply', '-f', '/tmp/ceph-secret.yaml']
check_call(cmd)
os.remove('/tmp/ceph-secret.yaml')
except: # NOQA
except: # NOQA
# the enlistment in kubernetes failed, return and prepare for re-exec
return
@ -760,7 +838,7 @@ def is_privileged():
"""Return boolean indicating whether or not to set allow-privileged=true.
"""
privileged = hookenv.config('allow-privileged')
privileged = hookenv.config('allow-privileged').lower()
if privileged == 'auto':
return is_state('kubernetes-master.gpu.enabled')
else:
@ -779,9 +857,11 @@ def on_config_allow_privileged_change():
@when('config.changed.api-extra-args')
@when('kubernetes-master.components.started')
@when('leadership.set.auto_storage_backend')
@when('etcd.available')
def on_config_api_extra_args_change(etcd):
configure_apiserver(etcd)
configure_apiserver(etcd.get_connection_string(),
getStorageBackend())
@when('config.changed.controller-manager-extra-args')
@ -806,7 +886,7 @@ def on_gpu_available(kube_control):
"""
config = hookenv.config()
if config['allow-privileged'] == "false":
if config['allow-privileged'].lower() == "false":
hookenv.status_set(
'active',
'GPUs available. Set allow-privileged="auto" to enable.'
@ -837,42 +917,25 @@ def shutdown():
service_stop('snap.kube-scheduler.daemon')
@when('kube-apiserver.do-restart')
def restart_apiserver():
prev_state, prev_msg = hookenv.status_get()
hookenv.status_set('maintenance', 'Restarting kube-apiserver')
host.service_restart('snap.kube-apiserver.daemon')
hookenv.status_set(prev_state, prev_msg)
remove_state('kube-apiserver.do-restart')
set_state('kube-apiserver.started')
@when('kube-controller-manager.do-restart')
def restart_controller_manager():
prev_state, prev_msg = hookenv.status_get()
hookenv.status_set('maintenance', 'Restarting kube-controller-manager')
host.service_restart('snap.kube-controller-manager.daemon')
hookenv.status_set(prev_state, prev_msg)
remove_state('kube-controller-manager.do-restart')
set_state('kube-controller-manager.started')
@when('kube-scheduler.do-restart')
def restart_scheduler():
prev_state, prev_msg = hookenv.status_get()
hookenv.status_set('maintenance', 'Restarting kube-scheduler')
host.service_restart('snap.kube-scheduler.daemon')
hookenv.status_set(prev_state, prev_msg)
remove_state('kube-scheduler.do-restart')
set_state('kube-scheduler.started')
@when_all('kube-apiserver.started',
'kube-controller-manager.started',
'kube-scheduler.started')
@when_not('kubernetes-master.components.started')
def componenets_started():
set_state('kubernetes-master.components.started')
def arch():
@ -951,9 +1014,16 @@ def create_kubeconfig(kubeconfig, server, ca, key=None, certificate=None,
def get_dns_ip():
'''Get an IP address for the DNS server on the provided cidr.'''
cmd = "kubectl get service --namespace kube-system kube-dns --output json"
output = check_output(cmd, shell=True).decode()
svc = json.loads(output)
return svc['spec']['clusterIP']
def get_deprecated_dns_ip():
'''We previously hardcoded the dns ip. This function returns the old
hardcoded value for use with older versions of cdk_addons.'''
interface = ipaddress.IPv4Interface(service_cidr())
# Add .10 at the end of the network
ip = interface.network.network_address + 10
return ip.exploded
@ -1018,7 +1088,7 @@ def configure_kubernetes_service(service, base_args, extra_args_key):
db.set(prev_args_key, args)
def configure_apiserver(etcd):
def configure_apiserver(etcd_connection_string, leader_etcd_version):
api_opts = {}
# Get the tls paths from the layer data.
@ -1048,11 +1118,12 @@ def configure_apiserver(etcd):
api_opts['logtostderr'] = 'true'
api_opts['insecure-bind-address'] = '127.0.0.1'
api_opts['insecure-port'] = '8080'
api_opts['storage-backend'] = 'etcd2' # FIXME: add etcd3 support
api_opts['storage-backend'] = leader_etcd_version
api_opts['basic-auth-file'] = '/root/cdk/basic_auth.csv'
api_opts['token-auth-file'] = '/root/cdk/known_tokens.csv'
api_opts['service-account-key-file'] = '/root/cdk/serviceaccount.key'
api_opts['kubelet-preferred-address-types'] = \
'[InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP]'
etcd_dir = '/root/cdk/etcd'
etcd_ca = os.path.join(etcd_dir, 'client-ca.pem')
@ -1062,7 +1133,7 @@ def configure_apiserver(etcd):
api_opts['etcd-cafile'] = etcd_ca
api_opts['etcd-keyfile'] = etcd_key
api_opts['etcd-certfile'] = etcd_cert
api_opts['etcd-servers'] = etcd.get_connection_string()
api_opts['etcd-servers'] = etcd_connection_string
admission_control = [
'Initializers',
@ -1088,8 +1159,7 @@ def configure_apiserver(etcd):
api_opts['admission-control'] = ','.join(admission_control)
configure_kubernetes_service('kube-apiserver', api_opts, 'api-extra-args')
set_state('kube-apiserver.do-restart')
restart_apiserver()
def configure_controller_manager():
@ -1099,7 +1169,7 @@ def configure_controller_manager():
layer_options = layer.options('tls-client')
ca_cert_path = layer_options.get('ca_certificate_path')
# Default to 3 minute resync. TODO: Make this configureable?
# Default to 3 minute resync. TODO: Make this configurable?
controller_opts['min-resync-period'] = '3m'
controller_opts['v'] = '2'
controller_opts['root-ca-file'] = ca_cert_path
@ -1111,8 +1181,7 @@ def configure_controller_manager():
configure_kubernetes_service('kube-controller-manager', controller_opts,
'controller-manager-extra-args')
set_state('kube-controller-manager.do-restart')
restart_controller_manager()
def configure_scheduler():
@ -1125,7 +1194,7 @@ def configure_scheduler():
configure_kubernetes_service('kube-scheduler', scheduler_opts,
'scheduler-extra-args')
set_state('kube-scheduler.do-restart')
restart_scheduler()
def setup_basic_auth(password=None, username='admin', uid='admin',
@ -1216,7 +1285,9 @@ def all_kube_system_pods_running():
result = json.loads(output)
for pod in result['items']:
status = pod['status']['phase']
if status != 'Running':
# Evicted nodes should re-spawn
if status != 'Running' and \
pod['status'].get('reason', '') != 'Evicted':
return False
return True
@ -1233,3 +1304,10 @@ def touch(fname):
os.utime(fname, None)
except OSError:
open(fname, 'a').close()
def getStorageBackend():
storage_backend = hookenv.config('storage-backend')
if storage_backend == 'auto':
storage_backend = leader_get('auto_storage_backend')
return storage_backend