Adding the Juju charms to the cluster directory.
This commit is contained in:
211
cluster/juju/charms/trusty/kubernetes-master/hooks/hooks.py
Executable file
211
cluster/juju/charms/trusty/kubernetes-master/hooks/hooks.py
Executable file
@@ -0,0 +1,211 @@
|
||||
#!/usr/bin/python
|
||||
"""
|
||||
The main hook file is called by Juju.
|
||||
"""
|
||||
import contextlib
|
||||
import os
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
from charmhelpers.core import hookenv, host
|
||||
from kubernetes_installer import KubernetesInstaller
|
||||
from path import path
|
||||
|
||||
hooks = hookenv.Hooks()
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def check_sentinel(filepath):
|
||||
"""
|
||||
A context manager method to write a file while the code block is doing
|
||||
something and remove the file when done.
|
||||
"""
|
||||
fail = False
|
||||
try:
|
||||
yield filepath.exists()
|
||||
except:
|
||||
fail = True
|
||||
filepath.touch()
|
||||
raise
|
||||
finally:
|
||||
if fail is False and filepath.exists():
|
||||
filepath.remove()
|
||||
|
||||
|
||||
@hooks.hook('config-changed')
|
||||
def config_changed():
|
||||
"""
|
||||
On the execution of the juju event 'config-changed' this function
|
||||
determines the appropriate architecture and the configured version to
|
||||
create kubernetes binary files.
|
||||
"""
|
||||
hookenv.log('Starting config-changed')
|
||||
charm_dir = path(hookenv.charm_dir())
|
||||
config = hookenv.config()
|
||||
# Get the version of kubernetes to install.
|
||||
version = config['version']
|
||||
# Get the package architecture, rather than the from the kernel (uname -m).
|
||||
arch = subprocess.check_output(['dpkg', '--print-architecture']).strip()
|
||||
kubernetes_dir = path('/opt/kubernetes')
|
||||
if not kubernetes_dir.exists():
|
||||
print('The source directory {0} does not exist'.format(kubernetes_dir))
|
||||
print('Was the kubernetes code cloned during install?')
|
||||
exit(1)
|
||||
|
||||
if version in ['source', 'head', 'master']:
|
||||
branch = 'master'
|
||||
else:
|
||||
# Create a branch to a tag.
|
||||
branch = 'tags/{0}'.format(version)
|
||||
|
||||
# Construct the path to the binaries using the arch.
|
||||
output_path = kubernetes_dir / '_output/local/bin/linux' / arch
|
||||
installer = KubernetesInstaller(arch, version, output_path)
|
||||
|
||||
# Change to the kubernetes directory (git repository).
|
||||
with kubernetes_dir:
|
||||
# Create a command to get the current branch.
|
||||
git_branch = 'git branch | grep "\*" | cut -d" " -f2'
|
||||
current_branch = subprocess.check_output(git_branch, shell=True).strip()
|
||||
print('Current branch: ', current_branch)
|
||||
# Create the path to a file to indicate if the build was broken.
|
||||
broken_build = charm_dir / '.broken_build'
|
||||
# write out the .broken_build file while this block is executing.
|
||||
with check_sentinel(broken_build) as last_build_failed:
|
||||
print('Last build failed: ', last_build_failed)
|
||||
# Rebuild if the current version is different or last build failed.
|
||||
if current_branch != version or last_build_failed:
|
||||
installer.build(branch)
|
||||
if not output_path.exists():
|
||||
broken_build.touch()
|
||||
else:
|
||||
print('Notifying minions of verison ' + version)
|
||||
# Notify the minions of a version change.
|
||||
for r in hookenv.relation_ids('minions-api'):
|
||||
hookenv.relation_set(r, version=version)
|
||||
print('Done notifing minions of version ' + version)
|
||||
|
||||
# Create the symoblic links to the right directories.
|
||||
installer.install()
|
||||
|
||||
relation_changed()
|
||||
|
||||
hookenv.log('The config-changed hook completed successfully.')
|
||||
|
||||
|
||||
@hooks.hook('etcd-relation-changed', 'minions-api-relation-changed')
|
||||
def relation_changed():
|
||||
template_data = get_template_data()
|
||||
|
||||
# Check required keys
|
||||
for k in ('etcd_servers',):
|
||||
if not template_data.get(k):
|
||||
print "Missing data for", k, template_data
|
||||
return
|
||||
|
||||
print "Running with\n", template_data
|
||||
|
||||
# Render and restart as needed
|
||||
for n in ('apiserver', 'controller-manager', 'scheduler'):
|
||||
if render_file(n, template_data) or not host.service_running(n):
|
||||
host.service_restart(n)
|
||||
|
||||
# Render the file that makes the kubernetes binaries available to minions.
|
||||
if render_file(
|
||||
'distribution', template_data,
|
||||
'conf.tmpl', '/etc/nginx/sites-enabled/distribution') or \
|
||||
not host.service_running('nginx'):
|
||||
host.service_reload('nginx')
|
||||
# Render the default nginx template.
|
||||
if render_file(
|
||||
'nginx', template_data,
|
||||
'conf.tmpl', '/etc/nginx/sites-enabled/default') or \
|
||||
not host.service_running('nginx'):
|
||||
host.service_reload('nginx')
|
||||
|
||||
# Send api endpoint to minions
|
||||
notify_minions()
|
||||
|
||||
|
||||
def notify_minions():
|
||||
print("Notify minions.")
|
||||
config = hookenv.config()
|
||||
for r in hookenv.relation_ids('minions-api'):
|
||||
hookenv.relation_set(
|
||||
r,
|
||||
hostname=hookenv.unit_private_ip(),
|
||||
port=8080,
|
||||
version=config['version'])
|
||||
|
||||
|
||||
def get_template_data():
|
||||
rels = hookenv.relations()
|
||||
config = hookenv.config()
|
||||
template_data = {}
|
||||
template_data['etcd_servers'] = ",".join([
|
||||
"http://%s:%s" % (s[0], s[1]) for s in sorted(
|
||||
get_rel_hosts('etcd', rels, ('hostname', 'port')))])
|
||||
template_data['minions'] = ",".join(get_rel_hosts('minions-api', rels))
|
||||
|
||||
template_data['api_bind_address'] = _bind_addr(hookenv.unit_private_ip())
|
||||
template_data['bind_address'] = "127.0.0.1"
|
||||
template_data['api_server_address'] = "http://%s:%s" % (
|
||||
hookenv.unit_private_ip(), 8080)
|
||||
arch = subprocess.check_output(['dpkg', '--print-architecture']).strip()
|
||||
template_data['web_uri'] = "/kubernetes/%s/local/bin/linux/%s/" % (
|
||||
config['version'], arch)
|
||||
_encode(template_data)
|
||||
return 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')
|
||||
|
||||
|
||||
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_file(name, data, src_suffix="upstart.tmpl", tgt_path=None):
|
||||
tmpl_path = os.path.join(
|
||||
os.environ.get('CHARM_DIR'), 'files', '%s.%s' % (name, src_suffix))
|
||||
|
||||
with open(tmpl_path) as fh:
|
||||
tmpl = fh.read()
|
||||
rendered = tmpl % data
|
||||
|
||||
if tgt_path is None:
|
||||
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
|
||||
|
||||
if __name__ == '__main__':
|
||||
hooks.execute(sys.argv)
|
Reference in New Issue
Block a user