update operator code for new config/pki
This commit is contained in:
parent
0ac46b6310
commit
9e7a8b8ba7
|
@ -18,9 +18,7 @@ def promenade(*, verbose):
|
||||||
type=click.Path(exists=True, file_okay=False,
|
type=click.Path(exists=True, file_okay=False,
|
||||||
dir_okay=True, resolve_path=True),
|
dir_okay=True, resolve_path=True),
|
||||||
help='Source path for binaries to deploy.')
|
help='Source path for binaries to deploy.')
|
||||||
@click.option('-c', '--config-path',
|
@click.option('-c', '--config-path', type=click.File(),
|
||||||
type=click.Path(exists=True, file_okay=True,
|
|
||||||
dir_okay=False, resolve_path=True),
|
|
||||||
help='Location of cluster configuration data.')
|
help='Location of cluster configuration data.')
|
||||||
@click.option('--hostname', help='Current hostname.')
|
@click.option('--hostname', help='Current hostname.')
|
||||||
@click.option('-t', '--target-dir', default='/target',
|
@click.option('-t', '--target-dir', default='/target',
|
||||||
|
@ -41,9 +39,7 @@ def genesis(*, asset_dir, config_path, hostname, target_dir):
|
||||||
type=click.Path(exists=True, file_okay=False,
|
type=click.Path(exists=True, file_okay=False,
|
||||||
dir_okay=True, resolve_path=True),
|
dir_okay=True, resolve_path=True),
|
||||||
help='Source path for binaries to deploy.')
|
help='Source path for binaries to deploy.')
|
||||||
@click.option('-c', '--config-path',
|
@click.option('-c', '--config-path', type=click.File(),
|
||||||
type=click.Path(exists=True, file_okay=True,
|
|
||||||
dir_okay=False, resolve_path=True),
|
|
||||||
help='Location of cluster configuration data.')
|
help='Location of cluster configuration data.')
|
||||||
@click.option('--hostname', help='Current hostname.')
|
@click.option('--hostname', help='Current hostname.')
|
||||||
@click.option('-t', '--target-dir', default='/target',
|
@click.option('-t', '--target-dir', default='/target',
|
||||||
|
|
|
@ -36,7 +36,9 @@ class Document:
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
assert set(data.keys()) == self.KEYS
|
if set(data.keys()) != self.KEYS:
|
||||||
|
LOG.error('data.keys()=%s expected %s', data.keys(), self.KEYS)
|
||||||
|
raise AssertionError('Did not get expected keys')
|
||||||
assert data['apiVersion'] == 'promenade/v1'
|
assert data['apiVersion'] == 'promenade/v1'
|
||||||
assert data['kind'] in self.SUPPORTED_KINDS
|
assert data['kind'] in self.SUPPORTED_KINDS
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from . import config, logging, pki, renderer
|
from . import config, logging, renderer
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
@ -10,18 +10,13 @@ LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
class Operator:
|
class Operator:
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_config(cls, *,
|
def from_config(cls, *, config_path, hostname, target_dir):
|
||||||
config_path,
|
|
||||||
hostname,
|
|
||||||
target_dir):
|
|
||||||
return cls(hostname=hostname, target_dir=target_dir,
|
return cls(hostname=hostname, target_dir=target_dir,
|
||||||
**config.load_config_file(config_path=config_path,
|
config_=config.load(config_path))
|
||||||
hostname=hostname))
|
|
||||||
|
|
||||||
def __init__(self, *, cluster_data, hostname, node_data, target_dir):
|
def __init__(self, *, config_, hostname, target_dir):
|
||||||
self.cluster_data = cluster_data
|
self.config = config_
|
||||||
self.hostname = hostname
|
self.hostname = hostname
|
||||||
self.node_data = node_data
|
|
||||||
self.target_dir = target_dir
|
self.target_dir = target_dir
|
||||||
|
|
||||||
def genesis(self, *, asset_dir=None):
|
def genesis(self, *, asset_dir=None):
|
||||||
|
@ -33,7 +28,6 @@ class Operator:
|
||||||
def setup(self, *, asset_dir):
|
def setup(self, *, asset_dir):
|
||||||
self.rsync_from(asset_dir)
|
self.rsync_from(asset_dir)
|
||||||
self.render()
|
self.render()
|
||||||
self.install_keys()
|
|
||||||
|
|
||||||
self.bootstrap()
|
self.bootstrap()
|
||||||
|
|
||||||
|
@ -48,14 +42,10 @@ class Operator:
|
||||||
|
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
r = renderer.Renderer(node_data=self.node_data,
|
r = renderer.Renderer(config=self.config,
|
||||||
target_dir=self.target_dir)
|
target_dir=self.target_dir)
|
||||||
r.render()
|
r.render()
|
||||||
|
|
||||||
def install_keys(self):
|
|
||||||
pki.generate_keys(initial_pki=self.cluster_data['pki'],
|
|
||||||
target_dir=self.target_dir)
|
|
||||||
|
|
||||||
def bootstrap(self):
|
def bootstrap(self):
|
||||||
LOG.debug('Running genesis script with chroot "%s"', self.target_dir)
|
LOG.debug('Running genesis script with chroot "%s"', self.target_dir)
|
||||||
subprocess.run([os.path.join(self.target_dir, 'usr/sbin/chroot'),
|
subprocess.run([os.path.join(self.target_dir, 'usr/sbin/chroot'),
|
||||||
|
|
134
promenade/pki.py
134
promenade/pki.py
|
@ -1,7 +1,6 @@
|
||||||
from . import config, logging
|
from . import config, logging
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import shutil
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
import yaml
|
import yaml
|
||||||
|
@ -153,136 +152,3 @@ def block_literal_representer(dumper, data):
|
||||||
|
|
||||||
|
|
||||||
yaml.add_representer(block_literal, block_literal_representer)
|
yaml.add_representer(block_literal, block_literal_representer)
|
||||||
|
|
||||||
|
|
||||||
CA_ONLY_MAP = {
|
|
||||||
'cluster-ca': [
|
|
||||||
'kubelet',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FULL_DISTRIBUTION_MAP = {
|
|
||||||
'apiserver': [
|
|
||||||
'apiserver',
|
|
||||||
],
|
|
||||||
'apiserver-key': [
|
|
||||||
'apiserver',
|
|
||||||
],
|
|
||||||
'controller-manager': [
|
|
||||||
'controller-manager',
|
|
||||||
],
|
|
||||||
'controller-manager-key': [
|
|
||||||
'controller-manager',
|
|
||||||
],
|
|
||||||
'kubelet': [
|
|
||||||
'kubelet',
|
|
||||||
],
|
|
||||||
'kubelet-key': [
|
|
||||||
'kubelet',
|
|
||||||
],
|
|
||||||
'proxy': [
|
|
||||||
'proxy',
|
|
||||||
],
|
|
||||||
'proxy-key': [
|
|
||||||
'proxy',
|
|
||||||
],
|
|
||||||
'scheduler': [
|
|
||||||
'scheduler',
|
|
||||||
],
|
|
||||||
'scheduler-key': [
|
|
||||||
'scheduler',
|
|
||||||
],
|
|
||||||
|
|
||||||
'cluster-ca': [
|
|
||||||
'admin',
|
|
||||||
'apiserver',
|
|
||||||
'asset-loader',
|
|
||||||
'controller-manager',
|
|
||||||
'etcd',
|
|
||||||
'genesis',
|
|
||||||
'kubelet',
|
|
||||||
'proxy',
|
|
||||||
'scheduler',
|
|
||||||
],
|
|
||||||
'cluster-ca-key': [
|
|
||||||
'controller-manager',
|
|
||||||
],
|
|
||||||
|
|
||||||
'sa': [
|
|
||||||
'apiserver',
|
|
||||||
],
|
|
||||||
'sa-key': [
|
|
||||||
'controller-manager',
|
|
||||||
],
|
|
||||||
|
|
||||||
'etcd': [
|
|
||||||
'etcd',
|
|
||||||
],
|
|
||||||
'etcd-key': [
|
|
||||||
'etcd',
|
|
||||||
],
|
|
||||||
|
|
||||||
'admin': [
|
|
||||||
'admin',
|
|
||||||
],
|
|
||||||
'admin-key': [
|
|
||||||
'admin',
|
|
||||||
],
|
|
||||||
'asset-loader': [
|
|
||||||
'asset-loader',
|
|
||||||
],
|
|
||||||
'asset-loader-key': [
|
|
||||||
'asset-loader',
|
|
||||||
],
|
|
||||||
'genesis': [
|
|
||||||
'genesis',
|
|
||||||
],
|
|
||||||
'genesis-key': [
|
|
||||||
'genesis',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def generate_keys(*, initial_pki, target_dir):
|
|
||||||
if os.path.exists(os.path.join(target_dir, 'etc/kubernetes/cfssl')):
|
|
||||||
with tempfile.TemporaryDirectory() as tmp:
|
|
||||||
_write_initial_pki(tmp, initial_pki)
|
|
||||||
|
|
||||||
_generate_certs(tmp, target_dir)
|
|
||||||
|
|
||||||
_distribute_files(tmp, target_dir, FULL_DISTRIBUTION_MAP)
|
|
||||||
|
|
||||||
|
|
||||||
def _write_initial_pki(tmp, initial_pki):
|
|
||||||
for filename, data in initial_pki.items():
|
|
||||||
path = os.path.join(tmp, filename + '.pem')
|
|
||||||
with open(path, 'w') as f:
|
|
||||||
LOG.debug('Writing data for "%s" to path "%s"', filename, path)
|
|
||||||
f.write(data)
|
|
||||||
|
|
||||||
|
|
||||||
def _generate_certs(dest, target):
|
|
||||||
ca_config_path = os.path.join(target, 'etc/kubernetes/cfssl/ca-config.json')
|
|
||||||
ca_path = os.path.join(dest, 'cluster-ca.pem')
|
|
||||||
ca_key_path = os.path.join(dest, 'cluster-ca-key.pem')
|
|
||||||
search_dir = os.path.join(target, 'etc/kubernetes/cfssl/csr-configs')
|
|
||||||
for filename in os.listdir(search_dir):
|
|
||||||
name, _ext = os.path.splitext(filename)
|
|
||||||
LOG.info('Generating cert for %s', name)
|
|
||||||
path = os.path.join(search_dir, filename)
|
|
||||||
cfssl_result = subprocess.check_output([
|
|
||||||
'cfssl', 'gencert', '-ca', ca_path, '-ca-key', ca_key_path,
|
|
||||||
'-config', ca_config_path, '-profile', 'kubernetes', path])
|
|
||||||
subprocess.run(['cfssljson', '-bare', name], cwd=dest,
|
|
||||||
input=cfssl_result, check=True)
|
|
||||||
|
|
||||||
|
|
||||||
def _distribute_files(src, dest, distribution_map):
|
|
||||||
for filename, destinations in distribution_map.items():
|
|
||||||
src_path = os.path.join(src, filename + '.pem')
|
|
||||||
if os.path.exists(src_path):
|
|
||||||
for destination in destinations:
|
|
||||||
dest_dir = os.path.join(dest, 'etc/kubernetes/%s/pki' % destination)
|
|
||||||
os.makedirs(dest_dir, exist_ok=True)
|
|
||||||
shutil.copy(src_path, dest_dir)
|
|
||||||
|
|
|
@ -10,19 +10,14 @@ LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Renderer:
|
class Renderer:
|
||||||
def __init__(self, *, node_data, target_dir):
|
def __init__(self, *, config, target_dir):
|
||||||
self.data = node_data
|
self.config = config
|
||||||
self.target_dir = target_dir
|
self.target_dir = target_dir
|
||||||
|
|
||||||
@property
|
|
||||||
def template_paths(self):
|
|
||||||
return ['common'] + self.data['current_node']['roles']
|
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
for template_dir in self.template_paths:
|
for template_dir in self.config['Node']['templates']:
|
||||||
self.render_template_dir(template_dir)
|
self.render_template_dir(template_dir)
|
||||||
|
|
||||||
|
|
||||||
def render_template_dir(self, template_dir):
|
def render_template_dir(self, template_dir):
|
||||||
source_root = pkg_resources.resource_filename(
|
source_root = pkg_resources.resource_filename(
|
||||||
'promenade', os.path.join('templates', template_dir))
|
'promenade', os.path.join('templates', template_dir))
|
||||||
|
@ -46,7 +41,7 @@ class Renderer:
|
||||||
|
|
||||||
with open(path) as f:
|
with open(path) as f:
|
||||||
template = env.from_string(f.read())
|
template = env.from_string(f.read())
|
||||||
rendered_data = template.render(**self.data)
|
rendered_data = template.render(config=self.config)
|
||||||
|
|
||||||
with open(target_path, 'w') as f:
|
with open(target_path, 'w') as f:
|
||||||
f.write(rendered_data)
|
f.write(rendered_data)
|
||||||
|
|
Loading…
Reference in New Issue