def configure_apiserver(): api_opts = {} # Get the tls paths from the layer data. layer_options = layer.options('tls-client') ca_cert_path = layer_options.get('ca_certificate_path') client_cert_path = layer_options.get('client_certificate_path') client_key_path = layer_options.get('client_key_path') server_cert_path = layer_options.get('server_certificate_path') server_key_path = layer_options.get('server_key_path') if is_privileged(): api_opts['allow-privileged'] = 'true' set_state('kubernetes-master.privileged') else: api_opts['allow-privileged'] = 'false' remove_state('kubernetes-master.privileged') # Handle static options for now api_opts['service-cluster-ip-range'] = service_cidr() api_opts['min-request-timeout'] = '300' api_opts['v'] = '4' api_opts['tls-cert-file'] = server_cert_path api_opts['tls-private-key-file'] = server_key_path api_opts['kubelet-certificate-authority'] = ca_cert_path api_opts['kubelet-client-certificate'] = client_cert_path api_opts['kubelet-client-key'] = client_key_path 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 admission_control = [ 'Initializers', 'NamespaceLifecycle', 'LimitRanger', 'ServiceAccount', 'ResourceQuota', 'DefaultTolerationSeconds' ] auth_mode = hookenv.config('authorization-mode') if 'Node' in auth_mode: admission_control.append('NodeRestriction') api_opts['authorization-mode'] = auth_mode if get_version('kube-apiserver') < (1, 6): hookenv.log('Removing DefaultTolerationSeconds from admission-control') admission_control.remove('DefaultTolerationSeconds') if get_version('kube-apiserver') < (1, 7): hookenv.log('Removing Initializers from admission-control') admission_control.remove('Initializers') api_opts['admission-control'] = ','.join(admission_control) configure_kubernetes_service('kube-apiserver', api_opts, 'api-extra-args') set_state('kube-apiserver.do-restart')
def enable_gpu(): """Enable GPU usage on this node. """ if get_version('kubelet') < (1, 9): hookenv.status_set( 'active', 'Upgrade to snap channel >= 1.9/stable to enable GPU suppport.') return hookenv.log('Enabling gpu mode') try: # Not sure why this is necessary, but if you don't run this, k8s will # think that the node has 0 gpus (as shown by the output of # `kubectl get nodes -o yaml` check_call(['nvidia-smi']) except CalledProcessError as cpe: hookenv.log('Unable to communicate with the NVIDIA driver.') hookenv.log(cpe) return set_label('gpu', 'true') set_label('cuda', 'true') set_state('kubernetes-worker.gpu.enabled') set_state('kubernetes-worker.restart-needed')
def enable_gpu(): """Enable GPU usage on this node. """ config = hookenv.config() if config['allow-privileged'] == "false": hookenv.status_set( 'active', 'GPUs available. Set allow-privileged="auto" to enable.') return hookenv.log('Enabling gpu mode') try: # Not sure why this is necessary, but if you don't run this, k8s will # think that the node has 0 gpus (as shown by the output of # `kubectl get nodes -o yaml` check_call(['nvidia-smi']) except CalledProcessError as cpe: hookenv.log('Unable to communicate with the NVIDIA driver.') hookenv.log(cpe) return kubelet_opts = FlagManager('kubelet') if get_version('kubelet') < (1, 6): hookenv.log('Adding --experimental-nvidia-gpus=1 to kubelet') kubelet_opts.add('experimental-nvidia-gpus', '1') else: hookenv.log('Adding --feature-gates=Accelerators=true to kubelet') kubelet_opts.add('feature-gates', 'Accelerators=true') # Apply node labels _apply_node_label('gpu=true', overwrite=True) _apply_node_label('cuda=true', overwrite=True) set_state('kubernetes-worker.gpu.enabled') set_state('kubernetes-worker.restart-needed')
def configure_cdk_addons(): ''' Configure CDK addons ''' remove_state('cdk-addons.configured') load_gpu_plugin = hookenv.config('enable-nvidia-plugin').lower() gpuEnable = (get_version('kube-apiserver') >= (1, 9) and load_gpu_plugin == "auto" and is_state('kubernetes-master.gpu.enabled')) dbEnabled = str(hookenv.config('enable-dashboard-addons')).lower() dnsEnabled = str(hookenv.config('enable-kube-dns')).lower() metricsEnabled = str(hookenv.config('enable-metrics')).lower() args = [ 'arch=' + arch(), 'dns-ip=' + get_deprecated_dns_ip(), 'dns-domain=' + hookenv.config('dns_domain'), 'enable-dashboard=' + dbEnabled, 'enable-kube-dns=' + dnsEnabled, 'enable-metrics=' + metricsEnabled, 'enable-gpu=' + str(gpuEnable).lower() ] check_call(['snap', 'set', 'cdk-addons'] + args) if not addons_ready(): remove_state('cdk-addons.configured') return set_state('cdk-addons.configured')
def gpu_with_no_privileged(): """We were in gpu mode, but the operator has set allow-privileged="false", so we can't run in gpu mode anymore. """ if get_version('kube-apiserver') < (1, 9): remove_state('kubernetes-master.gpu.enabled')
def configure_kubelet(dns): layer_options = layer.options('tls-client') ca_cert_path = layer_options.get('ca_certificate_path') server_cert_path = layer_options.get('server_certificate_path') server_key_path = layer_options.get('server_key_path') kubelet_opts = {} kubelet_opts['require-kubeconfig'] = 'true' kubelet_opts['kubeconfig'] = kubeconfig_path kubelet_opts['network-plugin'] = 'cni' kubelet_opts['v'] = '0' kubelet_opts['address'] = '0.0.0.0' kubelet_opts['port'] = '10250' kubelet_opts['cluster-dns'] = dns['sdn-ip'] kubelet_opts['cluster-domain'] = dns['domain'] kubelet_opts['anonymous-auth'] = 'false' kubelet_opts['client-ca-file'] = ca_cert_path kubelet_opts['tls-cert-file'] = server_cert_path kubelet_opts['tls-private-key-file'] = server_key_path kubelet_opts['logtostderr'] = 'true' kubelet_opts['fail-swap-on'] = 'false' privileged = is_state('kubernetes-worker.privileged') kubelet_opts['allow-privileged'] = 'true' if privileged else 'false' if is_state('kubernetes-worker.gpu.enabled'): if get_version('kubelet') < (1, 6): hookenv.log('Adding --experimental-nvidia-gpus=1 to kubelet') kubelet_opts['experimental-nvidia-gpus'] = '1' else: hookenv.log('Adding --feature-gates=Accelerators=true to kubelet') kubelet_opts['feature-gates'] = 'Accelerators=true' configure_kubernetes_service('kubelet', kubelet_opts, 'kubelet-extra-args')
def set_cloud_pending(): k8s_version = get_version('kubelet') k8s_1_11 = k8s_version >= (1, 11) k8s_1_12 = k8s_version >= (1, 12) vsphere_joined = is_state('endpoint.vsphere.joined') azure_joined = is_state('endpoint.azure.joined') if (vsphere_joined and not k8s_1_12) or (azure_joined and not k8s_1_11): set_state('kubernetes-worker.cloud.blocked') else: remove_state('kubernetes-worker.cloud.blocked') set_state('kubernetes-worker.cloud.pending')
def set_privileged(): """Update the allow-privileged flag for kubelet. """ privileged = hookenv.config('allow-privileged').lower() gpu_needs_privileged = (is_state('kubernetes-worker.gpu.enabled') and get_version('kubelet') < (1, 9)) if privileged == 'auto': privileged = 'true' if gpu_needs_privileged else 'false' if privileged == 'false' and gpu_needs_privileged: disable_gpu() remove_state('kubernetes-worker.gpu.enabled')
def on_gpu_available(kube_control): """The remote side (kubernetes-worker) is gpu-enabled. We need to run in privileged mode. """ kube_version = get_version('kube-apiserver') config = hookenv.config() if (config['allow-privileged'].lower() == "false" and kube_version < (1, 9)): return remove_state('kubernetes-master.components.started') set_state('kubernetes-master.gpu.enabled')
def set_privileged(): """Return 'true' if privileged containers are needed. This is when a) the user requested them b) user does not care (auto) and GPUs are available in a pre 1.9 era """ privileged = hookenv.config('allow-privileged').lower() gpu_needs_privileged = (is_state('kubernetes-worker.gpu.enabled') and get_version('kubelet') < (1, 9)) if privileged == 'auto': privileged = 'true' if gpu_needs_privileged else 'false' if privileged == 'false' and gpu_needs_privileged: disable_gpu() remove_state('kubernetes-worker.gpu.enabled') # No need to restart kubernetes (set the restart-needed state) # because set-privileged is already in the restart path return privileged
def disable_gpu(): """Disable GPU usage on this node. This handler fires when we're running in gpu mode, and then the operator sets allow-privileged="false". Since we can no longer run privileged containers, we need to disable gpu mode. """ hookenv.log('Disabling gpu mode') kubelet_opts = FlagManager('kubelet') if get_version('kubelet') < (1, 6): kubelet_opts.destroy('experimental-nvidia-gpus') else: kubelet_opts.remove('feature-gates', 'Accelerators=true') # Remove node labels _apply_node_label('gpu', delete=True) _apply_node_label('cuda', delete=True) remove_state('kubernetes-worker.gpu.enabled') set_state('kubernetes-worker.restart-needed')
def enable_gpu(): """Enable GPU usage on this node. """ config = hookenv.config() if config['allow-privileged'] == "false": hookenv.status_set( 'active', 'GPUs available. Set allow-privileged="auto" to enable.' ) return hookenv.log('Enabling gpu mode') kubelet_opts = FlagManager('kubelet') if get_version('kubelet') < (1, 6): hookenv.log('Adding --experimental-nvidia-gpus=1 to kubelet') kubelet_opts.add('--experimental-nvidia-gpus', '1') else: hookenv.log('Adding --feature-gates=Accelerators=true to kubelet') kubelet_opts.add('--feature-gates', 'Accelerators=true') # enable privileged mode and re-render config files set_privileged("true", render_config=False) render_init_scripts() # Apply node labels _apply_node_label('gpu=true', overwrite=True) _apply_node_label('cuda=true', overwrite=True) # Not sure why this is necessary, but if you don't run this, k8s will # think that the node has 0 gpus (as shown by the output of # `kubectl get nodes -o yaml` check_call(['nvidia-smi']) set_state('kubernetes-worker.gpu.enabled') set_state('kubernetes-worker.kubelet.restart')
def launch_default_ingress_controller(): ''' Launch the Kubernetes ingress controller & default backend (404) ''' config = hookenv.config() # need to test this in case we get in # here from a config change to the image if not config.get('ingress'): return context = {} context['arch'] = arch() addon_path = '/root/cdk/addons/{}' context['defaultbackend_image'] = config.get('default-backend-image') if (context['defaultbackend_image'] == "" or context['defaultbackend_image'] == "auto"): if context['arch'] == 's390x': context['defaultbackend_image'] = \ "k8s.gcr.io/defaultbackend-s390x:1.4" elif context['arch'] == 'arm64': context['defaultbackend_image'] = \ "k8s.gcr.io/defaultbackend-arm64:1.4" else: context['defaultbackend_image'] = \ "k8s.gcr.io/defaultbackend:1.4" # Render the default http backend (404) replicationcontroller manifest manifest = addon_path.format('default-http-backend.yaml') render('default-http-backend.yaml', manifest, context) hookenv.log('Creating the default http backend.') try: kubectl('apply', '-f', manifest) except CalledProcessError as e: hookenv.log(e) hookenv.log( 'Failed to create default-http-backend. Will attempt again next update.' ) # noqa hookenv.close_port(80) hookenv.close_port(443) return # Render the ingress daemon set controller manifest context['ingress_image'] = config.get('nginx-image') if context['ingress_image'] == "" or context['ingress_image'] == "auto": images = { 'amd64': 'quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.15.0', # noqa 'arm64': 'quay.io/kubernetes-ingress-controller/nginx-ingress-controller-arm64:0.15.0', # noqa 's390x': 'quay.io/kubernetes-ingress-controller/nginx-ingress-controller-s390x:0.15.0', # noqa 'ppc64el': 'quay.io/kubernetes-ingress-controller/nginx-ingress-controller-ppc64le:0.15.0', # noqa } context['ingress_image'] = images.get(context['arch'], images['amd64']) if get_version('kubelet') < (1, 9): context['daemonset_api_version'] = 'extensions/v1beta1' else: context['daemonset_api_version'] = 'apps/v1beta2' context['juju_application'] = hookenv.service_name() manifest = addon_path.format('ingress-daemon-set.yaml') render('ingress-daemon-set.yaml', manifest, context) hookenv.log('Creating the ingress daemon set.') try: kubectl('apply', '-f', manifest) except CalledProcessError as e: hookenv.log(e) hookenv.log( 'Failed to create ingress controller. Will attempt again next update.' ) # noqa hookenv.close_port(80) hookenv.close_port(443) return set_state('kubernetes-worker.ingress.available') hookenv.open_port(80) hookenv.open_port(443)
def configure_apiserver(etcd_connection_string, leader_etcd_version): api_opts = {} # Get the tls paths from the layer data. layer_options = layer.options('tls-client') ca_cert_path = layer_options.get('ca_certificate_path') client_cert_path = layer_options.get('client_certificate_path') client_key_path = layer_options.get('client_key_path') server_cert_path = layer_options.get('server_certificate_path') server_key_path = layer_options.get('server_key_path') # at one point in time, this code would set ca-client-cert, # but this was removed. This was before configure_kubernetes_service # kept track of old arguments and removed them, so client-ca-cert # was able to hang around forever stored in the snap configuration. # This removes that stale configuration from the snap if it still # exists. api_opts['client-ca-file'] = 'null' if is_privileged(): api_opts['allow-privileged'] = 'true' set_state('kubernetes-master.privileged') else: api_opts['allow-privileged'] = 'false' remove_state('kubernetes-master.privileged') # Handle static options for now api_opts['service-cluster-ip-range'] = service_cidr() api_opts['min-request-timeout'] = '300' api_opts['v'] = '4' api_opts['tls-cert-file'] = server_cert_path api_opts['tls-private-key-file'] = server_key_path api_opts['kubelet-certificate-authority'] = ca_cert_path api_opts['kubelet-client-certificate'] = client_cert_path api_opts['kubelet-client-key'] = client_key_path api_opts['logtostderr'] = 'true' api_opts['insecure-bind-address'] = '127.0.0.1' api_opts['insecure-port'] = '8080' 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]' api_opts['advertise-address'] = get_ingress_address('kube-control') etcd_dir = '/root/cdk/etcd' etcd_ca = os.path.join(etcd_dir, 'client-ca.pem') etcd_key = os.path.join(etcd_dir, 'client-key.pem') etcd_cert = os.path.join(etcd_dir, 'client-cert.pem') api_opts['etcd-cafile'] = etcd_ca api_opts['etcd-keyfile'] = etcd_key api_opts['etcd-certfile'] = etcd_cert api_opts['etcd-servers'] = etcd_connection_string admission_control_pre_1_9 = [ 'Initializers', 'NamespaceLifecycle', 'LimitRanger', 'ServiceAccount', 'ResourceQuota', 'DefaultTolerationSeconds' ] admission_control = [ 'NamespaceLifecycle', 'LimitRanger', 'ServiceAccount', 'PersistentVolumeLabel', 'DefaultStorageClass', 'DefaultTolerationSeconds', 'MutatingAdmissionWebhook', 'ValidatingAdmissionWebhook', 'ResourceQuota' ] auth_mode = hookenv.config('authorization-mode') if 'Node' in auth_mode: admission_control.append('NodeRestriction') api_opts['authorization-mode'] = auth_mode kube_version = get_version('kube-apiserver') if kube_version < (1, 6): hookenv.log('Removing DefaultTolerationSeconds from admission-control') admission_control_pre_1_9.remove('DefaultTolerationSeconds') if kube_version < (1, 7): hookenv.log('Removing Initializers from admission-control') admission_control_pre_1_9.remove('Initializers') if kube_version < (1, 9): api_opts['admission-control'] = ','.join(admission_control_pre_1_9) else: api_opts['admission-control'] = ','.join(admission_control) if kube_version > (1, 6) and \ hookenv.config('enable-metrics'): api_opts['requestheader-client-ca-file'] = ca_cert_path api_opts['requestheader-allowed-names'] = 'client' api_opts['requestheader-extra-headers-prefix'] = 'X-Remote-Extra-' api_opts['requestheader-group-headers'] = 'X-Remote-Group' api_opts['requestheader-username-headers'] = 'X-Remote-User' api_opts['proxy-client-cert-file'] = client_cert_path api_opts['proxy-client-key-file'] = client_key_path api_opts['enable-aggregator-routing'] = 'true' api_opts['client-ca-file'] = ca_cert_path configure_kubernetes_service('kube-apiserver', api_opts, 'api-extra-args') restart_apiserver()
def configure_master_services(): ''' Add remaining flags for the master services and configure snaps to use them ''' api_opts = FlagManager('kube-apiserver') controller_opts = FlagManager('kube-controller-manager') scheduler_opts = FlagManager('kube-scheduler') scheduler_opts.add('v', '2') # Get the tls paths from the layer data. layer_options = layer.options('tls-client') ca_cert_path = layer_options.get('ca_certificate_path') client_cert_path = layer_options.get('client_certificate_path') client_key_path = layer_options.get('client_key_path') server_cert_path = layer_options.get('server_certificate_path') server_key_path = layer_options.get('server_key_path') if is_privileged(): api_opts.add('allow-privileged', 'true', strict=True) set_state('kubernetes-master.privileged') else: api_opts.add('allow-privileged', 'false', strict=True) remove_state('kubernetes-master.privileged') # Handle static options for now api_opts.add('service-cluster-ip-range', service_cidr()) api_opts.add('min-request-timeout', '300') api_opts.add('v', '4') api_opts.add('client-ca-file', ca_cert_path) api_opts.add('tls-cert-file', server_cert_path) api_opts.add('tls-private-key-file', server_key_path) api_opts.add('kubelet-certificate-authority', ca_cert_path) api_opts.add('kubelet-client-certificate', client_cert_path) api_opts.add('kubelet-client-key', client_key_path) api_opts.add('logtostderr', 'true') api_opts.add('insecure-bind-address', '127.0.0.1') api_opts.add('insecure-port', '8080') api_opts.add('storage-backend', 'etcd2') # FIXME: add etcd3 support admission_control = [ 'NamespaceLifecycle', 'LimitRanger', 'ServiceAccount', 'ResourceQuota', 'DefaultTolerationSeconds' ] if get_version('kube-apiserver') < (1, 6): hookenv.log('Removing DefaultTolerationSeconds from admission-control') admission_control.remove('DefaultTolerationSeconds') api_opts.add('admission-control', ','.join(admission_control), strict=True) # Default to 3 minute resync. TODO: Make this configureable? controller_opts.add('min-resync-period', '3m') controller_opts.add('v', '2') controller_opts.add('root-ca-file', ca_cert_path) controller_opts.add('logtostderr', 'true') controller_opts.add('master', 'http://127.0.0.1:8080') scheduler_opts.add('v', '2') scheduler_opts.add('logtostderr', 'true') scheduler_opts.add('master', 'http://127.0.0.1:8080') cmd = ['snap', 'set', 'kube-apiserver'] + api_opts.to_s().split(' ') check_call(cmd) cmd = (['snap', 'set', 'kube-controller-manager'] + controller_opts.to_s().split(' ')) check_call(cmd) cmd = ['snap', 'set', 'kube-scheduler'] + scheduler_opts.to_s().split(' ') check_call(cmd)
def configure_apiserver(etcd_connection_string, leader_etcd_version): api_opts = {} # Get the tls paths from the layer data. layer_options = layer.options('tls-client') ca_cert_path = layer_options.get('ca_certificate_path') client_cert_path = layer_options.get('client_certificate_path') client_key_path = layer_options.get('client_key_path') server_cert_path = layer_options.get('server_certificate_path') server_key_path = layer_options.get('server_key_path') if is_privileged(): api_opts['allow-privileged'] = 'true' set_state('kubernetes-master.privileged') else: api_opts['allow-privileged'] = 'false' remove_state('kubernetes-master.privileged') # Handle static options for now api_opts['service-cluster-ip-range'] = service_cidr() api_opts['min-request-timeout'] = '300' api_opts['v'] = '4' api_opts['tls-cert-file'] = server_cert_path api_opts['tls-private-key-file'] = server_key_path api_opts['kubelet-certificate-authority'] = ca_cert_path api_opts['kubelet-client-certificate'] = client_cert_path api_opts['kubelet-client-key'] = client_key_path api_opts['logtostderr'] = 'true' api_opts['insecure-bind-address'] = '127.0.0.1' api_opts['insecure-port'] = '8080' 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') etcd_key = os.path.join(etcd_dir, 'client-key.pem') etcd_cert = os.path.join(etcd_dir, 'client-cert.pem') api_opts['etcd-cafile'] = etcd_ca api_opts['etcd-keyfile'] = etcd_key api_opts['etcd-certfile'] = etcd_cert api_opts['etcd-servers'] = etcd_connection_string admission_control = [ 'Initializers', 'NamespaceLifecycle', 'LimitRanger', 'ServiceAccount', 'ResourceQuota', 'DefaultTolerationSeconds' ] auth_mode = hookenv.config('authorization-mode') if 'Node' in auth_mode: admission_control.append('NodeRestriction') api_opts['authorization-mode'] = auth_mode if get_version('kube-apiserver') < (1, 6): hookenv.log('Removing DefaultTolerationSeconds from admission-control') admission_control.remove('DefaultTolerationSeconds') if get_version('kube-apiserver') < (1, 7): hookenv.log('Removing Initializers from admission-control') admission_control.remove('Initializers') api_opts['admission-control'] = ','.join(admission_control) configure_kubernetes_service('kube-apiserver', api_opts, 'api-extra-args') restart_apiserver()
def configure_apiserver(): # TODO: investigate if it's possible to use config file to store args # https://github.com/juju-solutions/bundle-canonical-kubernetes/issues/315 # Handle api-extra-args config option to_add, to_remove = get_config_args() api_opts = FlagManager('kube-apiserver') # Remove arguments that are no longer provided as config option # this allows them to be reverted to charm defaults for arg in to_remove: hookenv.log('Removing option: {}'.format(arg)) api_opts.destroy(arg) # We need to "unset" options by settig their value to "null" string cmd = ['snap', 'set', 'kube-apiserver', '{}=null'.format(arg)] check_call(cmd) # Get the tls paths from the layer data. layer_options = layer.options('tls-client') ca_cert_path = layer_options.get('ca_certificate_path') client_cert_path = layer_options.get('client_certificate_path') client_key_path = layer_options.get('client_key_path') server_cert_path = layer_options.get('server_certificate_path') server_key_path = layer_options.get('server_key_path') if is_privileged(): api_opts.add('allow-privileged', 'true', strict=True) set_state('kubernetes-master.privileged') else: api_opts.add('allow-privileged', 'false', strict=True) remove_state('kubernetes-master.privileged') # Handle static options for now api_opts.add('service-cluster-ip-range', service_cidr()) api_opts.add('min-request-timeout', '300') api_opts.add('v', '4') api_opts.add('tls-cert-file', server_cert_path) api_opts.add('tls-private-key-file', server_key_path) api_opts.add('kubelet-certificate-authority', ca_cert_path) api_opts.add('kubelet-client-certificate', client_cert_path) api_opts.add('kubelet-client-key', client_key_path) api_opts.add('logtostderr', 'true') api_opts.add('insecure-bind-address', '127.0.0.1') api_opts.add('insecure-port', '8080') api_opts.add('storage-backend', 'etcd2') # FIXME: add etcd3 support admission_control = [ 'Initializers', 'NamespaceLifecycle', 'LimitRanger', 'ServiceAccount', 'ResourceQuota', 'DefaultTolerationSeconds' ] auth_mode = hookenv.config('authorization-mode') if 'Node' in auth_mode: admission_control.append('NodeRestriction') api_opts.add('authorization-mode', auth_mode, strict=True) if get_version('kube-apiserver') < (1, 6): hookenv.log('Removing DefaultTolerationSeconds from admission-control') admission_control.remove('DefaultTolerationSeconds') if get_version('kube-apiserver') < (1, 7): hookenv.log('Removing Initializers from admission-control') admission_control.remove('Initializers') api_opts.add('admission-control', ','.join(admission_control), strict=True) # Add operator-provided arguments, this allows operators # to override defaults for arg in to_add: hookenv.log('Adding option: {} {}'.format(arg[0], arg[1])) # Make sure old value is gone api_opts.destroy(arg[0]) api_opts.add(arg[0], arg[1]) cmd = ['snap', 'set', 'kube-apiserver'] + api_opts.to_s().split(' ') check_call(cmd) set_state('kube-apiserver.do-restart')
def configure_kubelet(dns, ingress_ip): layer_options = layer.options('tls-client') ca_cert_path = layer_options.get('ca_certificate_path') server_cert_path = layer_options.get('server_certificate_path') server_key_path = layer_options.get('server_key_path') kubelet_opts = {} kubelet_opts['require-kubeconfig'] = 'true' kubelet_opts['kubeconfig'] = kubeconfig_path kubelet_opts['network-plugin'] = 'cni' kubelet_opts['v'] = '0' kubelet_opts['logtostderr'] = 'true' kubelet_opts['node-ip'] = ingress_ip kubelet_opts['allow-privileged'] = set_privileged() kubelet_cloud_config_path = cloud_config_path('kubelet') if is_state('endpoint.aws.ready'): kubelet_opts['cloud-provider'] = 'aws' elif is_state('endpoint.gcp.ready'): kubelet_opts['cloud-provider'] = 'gce' kubelet_opts['cloud-config'] = str(kubelet_cloud_config_path) elif is_state('endpoint.openstack.ready'): kubelet_opts['cloud-provider'] = 'openstack' kubelet_opts['cloud-config'] = str(kubelet_cloud_config_path) elif is_state('endpoint.vsphere.joined'): # vsphere just needs to be joined on the worker (vs 'ready') kubelet_opts['cloud-provider'] = 'vsphere' # NB: vsphere maps node product-id to its uuid (no config file needed). uuid_file = '/sys/class/dmi/id/product_uuid' with open(uuid_file, 'r') as f: uuid = f.read().strip() kubelet_opts['provider-id'] = 'vsphere://{}'.format(uuid) elif is_state('endpoint.azure.ready'): azure = endpoint_from_flag('endpoint.azure.ready') kubelet_opts['cloud-provider'] = 'azure' kubelet_opts['cloud-config'] = str(kubelet_cloud_config_path) kubelet_opts['provider-id'] = azure.vm_id if get_version('kubelet') >= (1, 10): # Put together the KubeletConfiguration data kubelet_config = { 'apiVersion': 'kubelet.config.k8s.io/v1beta1', 'kind': 'KubeletConfiguration', 'address': '0.0.0.0', 'authentication': { 'anonymous': { 'enabled': False }, 'x509': { 'clientCAFile': ca_cert_path } }, 'clusterDomain': dns['domain'], 'failSwapOn': False, 'port': 10250, 'tlsCertFile': server_cert_path, 'tlsPrivateKeyFile': server_key_path } if dns['enable-kube-dns']: kubelet_config['clusterDNS'] = [dns['sdn-ip']] if is_state('kubernetes-worker.gpu.enabled'): kubelet_config['featureGates'] = {'DevicePlugins': True} # Add kubelet-extra-config. This needs to happen last so that it # overrides any config provided by the charm. kubelet_extra_config = hookenv.config('kubelet-extra-config') kubelet_extra_config = yaml.load(kubelet_extra_config) merge_kubelet_extra_config(kubelet_config, kubelet_extra_config) # Render the file and configure Kubelet to use it os.makedirs('/root/cdk/kubelet', exist_ok=True) with open('/root/cdk/kubelet/config.yaml', 'w') as f: f.write('# Generated by kubernetes-worker charm, do not edit\n') yaml.dump(kubelet_config, f) kubelet_opts['config'] = '/root/cdk/kubelet/config.yaml' else: # NOTE: This is for 1.9. Once we've dropped 1.9 support, we can remove # this whole block and the parent if statement. kubelet_opts['address'] = '0.0.0.0' kubelet_opts['anonymous-auth'] = 'false' kubelet_opts['client-ca-file'] = ca_cert_path kubelet_opts['cluster-domain'] = dns['domain'] kubelet_opts['fail-swap-on'] = 'false' kubelet_opts['port'] = '10250' kubelet_opts['tls-cert-file'] = server_cert_path kubelet_opts['tls-private-key-file'] = server_key_path if dns['enable-kube-dns']: kubelet_opts['cluster-dns'] = dns['sdn-ip'] if is_state('kubernetes-worker.gpu.enabled'): kubelet_opts['feature-gates'] = 'DevicePlugins=true' if get_version('kubelet') >= (1, 11): kubelet_opts['dynamic-config-dir'] = '/root/cdk/kubelet/dynamic-config' configure_kubernetes_service(configure_prefix, 'kubelet', kubelet_opts, 'kubelet-extra-args')