
Squashed commit of the following:
commit dedaccffdc1d797b5f23e0004280c2fcc0ecffa9
Merge: 24c3585 f03a267
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Tue Sep 15 17:07:42 2015 -0500
Merge branch 'master' of github.com:kubernetes/kubernetes into enable-ssl
commit 24c358566cc0963fb86dc057db15739f031ba6f6
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Tue Sep 15 16:44:58 2015 -0500
Fixing problems with verify-boilerplate.
commit a64443352c64498255ac98fc0da1a7d8d5934485
Merge: f152794 ee3f662
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Tue Sep 15 15:43:08 2015 -0500
Merge branch 'enable-ssl' of github.com:mbruzek/kubernetes into enable-ssl
Conflicts:
cluster/juju/util.sh
commit f152794502c017ae7d3cff0351d8bf44b7311883
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 14:12:21 2015 -0500
Fixes for problems found in testing.
commit 94effa4827d5f30c60621e9133c4526c187e40b4
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 12:34:37 2015 -0500
Making updates for changes in master branch.
commit a81795b44e57d54b8b4ae486ca6ea8164ac8fc6b
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 11:39:36 2015 -0500
pep8 fix
commit 53a862caea02c4b35f8cd19b1549fda29e040f12
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 11:37:31 2015 -0500
Adding diagnostic log messages and reloading nginx.
commit 96411a924fb05e2e58534cce94d9a1e51d7db9af
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 11:19:31 2015 -0500
Making the check user logic cleaner.
commit a0243b34cdda2f865e559bd4812c5a78ab6f6f05
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 11:18:04 2015 -0500
Open port 6443 for ssl enablement.
commit e8423614763aa6d650089c735c3dc1893bf73993
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 11:16:54 2015 -0500
Generating certificates and adding config options.
commit 6570a818e252f2cb156a577094ba987dec834fe1
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 11:14:56 2015 -0500
Removing the http configuration adding https config.
commit e624bd79f8840b71b141a111bca7c6091b677575
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 11:13:04 2015 -0500
Changed the distribution nginx config slightly.
commit c497911170268ee75bed53afeb5fa32ff44c82af
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 10:57:17 2015 -0500
Adding the crt and key to the apiserver flags.
commit 6c1e76c5de31eb4d0f800065ce4bc96a82801846
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 10:56:15 2015 -0500
Adding the cert and key configuration parameters.
commit 55da910d473efa0be0af5efccf2336612525986e
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 10:49:46 2015 -0500
Adding a requirements file to install path.py with pip -r
commit 27a39686af89e134268be50ce5e4fc36cffdf2b3
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Fri Aug 21 16:34:56 2015 -0500
Making the install hook idempotent.
commit ee3f66287ba045592f932c3a41aeb8e0167a9235
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 14:12:21 2015 -0500
Fixes for problems found in testing.
commit 3dfdbb0e21d79da66617f7a29e6dd8d977528057
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 12:34:37 2015 -0500
Making updates for changes in master branch.
commit df9c297fe27c63713fc0d7dbd461b2d47133614c
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 11:39:36 2015 -0500
pep8 fix
commit 645b25d9cc84555ca7af5c75e3f0b1300aaa9f48
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 11:37:31 2015 -0500
Adding diagnostic log messages and reloading nginx.
commit 57654320bd73dc4dd52d6d56021d40a97c6ed893
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 11:37:02 2015 -0500
Removing xtrace.
commit a0e8cd98353e7cd411786bc8836fe99a77cde3ba
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 11:19:31 2015 -0500
Making the check user logic cleaner.
commit 6c6eb7ff02d6dbf66d3175b715e957b00a861525
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 11:18:04 2015 -0500
Open port 6443 for ssl enablement.
commit 29f18cc95ff96de1a48f72af2cff2e37420a43c7
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 11:16:54 2015 -0500
Generating certificates and adding config options.
commit c9bdaa499552980153ff263a1ab9b4fa73a0536a
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 11:14:56 2015 -0500
Removing the http configuration adding https config.
commit ec33e66a159a4b44207353b16741c7fad2e4ee0d
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 11:13:04 2015 -0500
Changed the distribution nginx config slightly.
commit 96dc16879c0dd230569ceb928f9f7bf92ff8ab3f
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 10:57:17 2015 -0500
Adding the crt and key to the apiserver flags.
commit 308799502c0a22f214408395f5efa4821d075374
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 10:56:15 2015 -0500
Adding the cert and key configuration parameters.
commit 7f407a4356de8703ff2f237432084f35910d8abd
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Wed Sep 9 10:49:46 2015 -0500
Adding a requirements file to install path.py with pip -r
commit f800ae1152076758d4db203fdbecf6d945c0e892
Author: Matt Bruzek <matthew.bruzek@canonical.com>
Date: Fri Aug 21 16:34:56 2015 -0500
Making the install hook idempotent.
Resolving verification problems.
240 lines
7.9 KiB
Python
Executable File
240 lines
7.9 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
# Copyright 2015 The Kubernetes Authors All rights reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""
|
|
The main hook file that is called by Juju.
|
|
"""
|
|
import os
|
|
import socket
|
|
import subprocess
|
|
import sys
|
|
import urlparse
|
|
|
|
from charmhelpers.core import hookenv, host
|
|
from kubernetes_installer import KubernetesInstaller
|
|
from path import Path
|
|
|
|
from lib.registrator import Registrator
|
|
|
|
hooks = hookenv.Hooks()
|
|
|
|
|
|
@hooks.hook('api-relation-changed')
|
|
def api_relation_changed():
|
|
"""
|
|
On the relation to the api server, this function determines the appropriate
|
|
architecture and the configured version to copy the kubernetes binary files
|
|
from the kubernetes-master charm and installs it locally on this machine.
|
|
"""
|
|
hookenv.log('Starting api-relation-changed')
|
|
charm_dir = Path(hookenv.charm_dir())
|
|
# Get the package architecture, rather than the from the kernel (uname -m).
|
|
arch = subprocess.check_output(['dpkg', '--print-architecture']).strip()
|
|
kubernetes_bin_dir = Path('/opt/kubernetes/bin')
|
|
# Get the version of kubernetes to install.
|
|
version = subprocess.check_output(['relation-get', 'version']).strip()
|
|
print('Relation version: ', version)
|
|
if not version:
|
|
print('No version present in the relation.')
|
|
exit(0)
|
|
version_file = charm_dir / '.version'
|
|
if version_file.exists():
|
|
previous_version = version_file.text()
|
|
print('Previous version: ', previous_version)
|
|
if version == previous_version:
|
|
exit(0)
|
|
# Can not download binaries while the service is running, so stop it.
|
|
# TODO: Figure out a better way to handle upgraded kubernetes binaries.
|
|
for service in ('kubelet', 'proxy'):
|
|
if host.service_running(service):
|
|
host.service_stop(service)
|
|
command = ['relation-get', 'private-address']
|
|
# Get the kubernetes-master address.
|
|
server = subprocess.check_output(command).strip()
|
|
print('Kubernetes master private address: ', server)
|
|
installer = KubernetesInstaller(arch, version, server, kubernetes_bin_dir)
|
|
installer.download()
|
|
installer.install()
|
|
# Write the most recently installed version number to the file.
|
|
version_file.write_text(version)
|
|
relation_changed()
|
|
|
|
|
|
@hooks.hook('etcd-relation-changed',
|
|
'network-relation-changed')
|
|
def relation_changed():
|
|
"""Connect the parts and go :-)
|
|
"""
|
|
template_data = get_template_data()
|
|
|
|
# Check required keys
|
|
for k in ('etcd_servers', 'kubeapi_server'):
|
|
if not template_data.get(k):
|
|
print('Missing data for %s %s' % (k, template_data))
|
|
return
|
|
print('Running with\n%s' % template_data)
|
|
|
|
# Setup kubernetes supplemental group
|
|
setup_kubernetes_group()
|
|
|
|
# Register upstart managed services
|
|
for n in ('kubelet', 'proxy'):
|
|
if render_upstart(n, template_data) or not host.service_running(n):
|
|
print('Starting %s' % n)
|
|
host.service_restart(n)
|
|
|
|
# Register machine via api
|
|
print('Registering machine')
|
|
register_machine(template_data['kubeapi_server'])
|
|
|
|
# Save the marker (for restarts to detect prev install)
|
|
template_data.save()
|
|
|
|
|
|
def get_template_data():
|
|
rels = hookenv.relations()
|
|
template_data = hookenv.Config()
|
|
template_data.CONFIG_FILE_NAME = '.unit-state'
|
|
|
|
overlay_type = get_scoped_rel_attr('network', rels, 'overlay_type')
|
|
etcd_servers = get_rel_hosts('etcd', rels, ('hostname', 'port'))
|
|
api_servers = get_rel_hosts('api', rels, ('hostname', 'port'))
|
|
|
|
# kubernetes master isn't ha yet.
|
|
if api_servers:
|
|
api_info = api_servers.pop()
|
|
api_servers = 'http://%s:%s' % (api_info[0], api_info[1])
|
|
|
|
template_data['overlay_type'] = overlay_type
|
|
template_data['kubelet_bind_addr'] = _bind_addr(
|
|
hookenv.unit_private_ip())
|
|
template_data['proxy_bind_addr'] = _bind_addr(
|
|
hookenv.unit_get('public-address'))
|
|
template_data['kubeapi_server'] = api_servers
|
|
template_data['etcd_servers'] = ','.join([
|
|
'http://%s:%s' % (s[0], s[1]) for s in sorted(etcd_servers)])
|
|
template_data['identifier'] = os.environ['JUJU_UNIT_NAME'].replace(
|
|
'/', '-')
|
|
return _encode(template_data)
|
|
|
|
|
|
def _bind_addr(addr):
|
|
if addr.replace('.', '').isdigit():
|
|
return addr
|
|
try:
|
|
return socket.gethostbyname(addr)
|
|
except socket.error:
|
|
raise ValueError('Could not resolve private address')
|
|
|
|
|
|
def _encode(d):
|
|
for k, v in d.items():
|
|
if isinstance(v, unicode):
|
|
d[k] = v.encode('utf8')
|
|
return d
|
|
|
|
|
|
def get_scoped_rel_attr(rel_name, rels, attr):
|
|
private_ip = hookenv.unit_private_ip()
|
|
for r, data in rels.get(rel_name, {}).items():
|
|
for unit_id, unit_data in data.items():
|
|
if unit_data.get('private-address') != private_ip:
|
|
continue
|
|
if unit_data.get(attr):
|
|
return unit_data.get(attr)
|
|
|
|
|
|
def get_rel_hosts(rel_name, rels, keys=('private-address',)):
|
|
hosts = []
|
|
for r, data in rels.get(rel_name, {}).items():
|
|
for unit_id, unit_data in data.items():
|
|
if unit_id == hookenv.local_unit():
|
|
continue
|
|
values = [unit_data.get(k) for k in keys]
|
|
if not all(values):
|
|
continue
|
|
hosts.append(len(values) == 1 and values[0] or values)
|
|
return hosts
|
|
|
|
|
|
def render_upstart(name, data):
|
|
tmpl_path = os.path.join(
|
|
os.environ.get('CHARM_DIR'), 'files', '%s.upstart.tmpl' % name)
|
|
|
|
with open(tmpl_path) as fh:
|
|
tmpl = fh.read()
|
|
rendered = tmpl % data
|
|
|
|
tgt_path = '/etc/init/%s.conf' % name
|
|
|
|
if os.path.exists(tgt_path):
|
|
with open(tgt_path) as fh:
|
|
contents = fh.read()
|
|
if contents == rendered:
|
|
return False
|
|
|
|
with open(tgt_path, 'w') as fh:
|
|
fh.write(rendered)
|
|
return True
|
|
|
|
|
|
def register_machine(apiserver, retry=False):
|
|
parsed = urlparse.urlparse(apiserver)
|
|
# identity = hookenv.local_unit().replace('/', '-')
|
|
private_address = hookenv.unit_private_ip()
|
|
|
|
with open('/proc/meminfo') as fh:
|
|
info = fh.readline()
|
|
mem = info.strip().split(':')[1].strip().split()[0]
|
|
cpus = os.sysconf('SC_NPROCESSORS_ONLN')
|
|
|
|
# https://github.com/kubernetes/kubernetes/blob/master/docs/admin/node.md
|
|
registration_request = Registrator()
|
|
registration_request.data['kind'] = 'Node'
|
|
registration_request.data['id'] = private_address
|
|
registration_request.data['name'] = private_address
|
|
registration_request.data['metadata']['name'] = private_address
|
|
registration_request.data['spec']['capacity']['mem'] = mem + ' K'
|
|
registration_request.data['spec']['capacity']['cpu'] = cpus
|
|
registration_request.data['spec']['externalID'] = private_address
|
|
registration_request.data['status']['hostIP'] = private_address
|
|
|
|
response, result = registration_request.register(parsed.hostname,
|
|
parsed.port,
|
|
'/api/v1/nodes')
|
|
|
|
print(response)
|
|
|
|
try:
|
|
registration_request.command_succeeded(response, result)
|
|
except ValueError:
|
|
# This happens when we have already registered
|
|
# for now this is OK
|
|
pass
|
|
|
|
|
|
def setup_kubernetes_group():
|
|
output = subprocess.check_output(['groups', 'kubernetes'])
|
|
|
|
# TODO: check group exists
|
|
if 'docker' not in output:
|
|
subprocess.check_output(
|
|
['usermod', '-a', '-G', 'docker', 'kubernetes'])
|
|
|
|
|
|
if __name__ == '__main__':
|
|
hooks.execute(sys.argv)
|