Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
datasource_list: [ Ec2Kubernetes ]
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# This file is part of cloud-init. See LICENSE file for license information.

import logging
import os

from cloudinit import handlers, helpers, sources, util
from cloudinit.handlers.boot_hook import BootHookPartHandler
from cloudinit.handlers.jinja_template import JinjaTemplatePartHandler
from cloudinit.handlers.cloud_config import CloudConfigPartHandler
from cloudinit.handlers.shell_script import ShellScriptPartHandler
from cloudinit.settings import PER_ALWAYS
from cloudinit.sources import DataSourceEc2
from cloudinit.handlers.jinja_template import (
render_jinja_payload_from_file,
)

LOG = logging.getLogger(__name__)


class BootHookPartHandlerModified(BootHookPartHandler):
def __init__(self, paths, datasource, **_kwargs):
super().__init__(paths, datasource)
self.output = None

def handle_part(self, data, ctype, filename, payload, frequency):
"""Save the output of the script"""
if ctype in handlers.CONTENT_SIGNALS:
return

# modify the payload to not restart cloud-init
# TODO: work with upstream to remove this restart
restart_index = payload.find("systemctl restart cloud-init")
if -1 != restart_index:
LOG.warning(
"Kubernetes is trying to restart cloud-init. This is no "
"longer necessary and is temporarily circumvented by "
"cloud-init. This will be a hard error in the future."
)
payload = payload[:restart_index] + "#" + payload[restart_index:]
super().handle_part(data, ctype, filename, payload, frequency)


class DataSourceEc2Kubernetes(DataSourceEc2.DataSourceEc2):
def _get_data(self):
super()._get_data()

# Get initial user-data
user_data_msg = self.get_userdata(True)
LOG.info("User-data received:[\n%s]", user_data_msg)
self.persist_instance_data()

# This is required to get path of the instance
self.paths.datasource = self

# Boilerplate handler setup
c_handlers = helpers.ContentHandlers()
cloudconfig_handler = CloudConfigPartHandler(self.paths)
shellscript_handler = ShellScriptPartHandler(self.paths)
boothook_handler = BootHookPartHandlerModified(self.paths, self)
jinja_handler = JinjaTemplatePartHandler(
self.paths,
sub_handlers=[
cloudconfig_handler,
shellscript_handler,
boothook_handler,
],
)
c_handlers.register(boothook_handler, overwrite=False)
c_handlers.register(jinja_handler, overwrite=False)
LOG.debug("Registered handlers %s and %s", boothook_handler, jinja_handler)

# Walk the user data MIME
handlers.walk(
user_data_msg,
handlers.walker_callback,
data={
"handlers": c_handlers,
"handlerdir": self.paths.get_ipath("handlers"),
"data": None,
"frequency": PER_ALWAYS,
"handlercount": 0,
"excluded": [],
},
)
LOG.info("User-data before update:[\n%s]", self.userdata_raw)
secret_userdata = "/etc/secret-userdata.txt"
# Get the boothook output, save it as user-data
# TODO: work with upstream to put this somewhere more sensible like:
# /var/lib/cloud/instances/{{v1.instance_id}}/ec2-kubernetes-userdata.txt
userdata_raw = util.load_text_file(secret_userdata)
LOG.info("Secret user-data:[\n%s]", self.userdata_raw)

uid = os.getuid()
redacted_data_fn = self.paths.get_runpath("instance_data")
if uid == 0:
instance_data_fn = self.paths.get_runpath("instance_data_sensitive")
if not os.path.exists(instance_data_fn):
LOG.warning(
"Missing root-readable %s. Using redacted %s instead.",
instance_data_fn,
redacted_data_fn,
)
instance_data_fn = redacted_data_fn
else:
instance_data_fn = redacted_data_fn
rendered_payload = render_jinja_payload_from_file(
payload=userdata_raw,
payload_fn=secret_userdata,
instance_data_file=instance_data_fn,
)
util.write_file(
"/etc/cloud/cloud.cfg.d/99_kubeadm_bootstrap.cfg", rendered_payload
)
self.userdata_raw = rendered_payload
return True


class DataSourceEc2KubernetesLocal(DataSourceEc2Kubernetes):
def _get_data(self):
return super(DataSourceEc2KubernetesLocal, self).get_data()


# Used to match classes to dependencies
datasources = [
(
DataSourceEc2KubernetesLocal,
(sources.DEP_FILESYSTEM,),
),
(DataSourceEc2Kubernetes, (sources.DEP_FILESYSTEM, sources.DEP_NETWORK)),
]


# Return a list of data sources that match this set of dependencies
def get_datasource_list(depends):
return sources.list_from_depends(depends, datasources)
18 changes: 18 additions & 0 deletions images/capi/ansible/roles/providers/tasks/aws.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,21 @@
state: stopped
enabled: false
when: ansible_os_family == "Debian"

- name: Create cloud-init custom data source list
ansible.builtin.copy:
src: files/etc/cloud/cloud.cfg.d/90_dpkg.cfg
dest: /etc/cloud/cloud.cfg.d/90_dpkg.cfg
owner: root
group: root
mode: "0644"
when: ansible_distribution == "Ubuntu" and ansible_distribution_version is version('22.04', '>=')

- name: Create custom cloud-init data source
ansible.builtin.copy:
src: usr/lib/python3/dist-packages/cloudinit/sources/DataSourceEc2Kubernetes.py
dest: /usr/lib/python3/dist-packages/cloudinit/sources/DataSourceEc2Kubernetes.py
owner: root
group: root
mode: "0644"
when: ansible_distribution == "Ubuntu" and ansible_distribution_version is version('22.04', '>=')
2 changes: 1 addition & 1 deletion images/capi/packer/ami/ubuntu-2204.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"ami_filter_name": "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*",
"ami_filter_owners": "099720109477",
"ansible_extra_vars": "pinned_debs=\"cloud-init=23.1.2-0ubuntu0~22.04.1\"",
"ansible_extra_vars": "",
"build_name": "ubuntu-22.04",
"distribution": "Ubuntu",
"distribution_release": "jammy",
Expand Down
2 changes: 1 addition & 1 deletion images/capi/packer/ami/ubuntu-2404.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"ami_filter_name": "ubuntu/images/*ubuntu-noble-24.04-amd64-server-*",
"ami_filter_owners": "099720109477",
"ansible_extra_vars": "pinned_debs=\"cloud-init=24.1.3-0ubuntu3\"",
"ansible_extra_vars": "",
"build_name": "ubuntu-24.04",
"distribution": "Ubuntu",
"distribution_release": "noble",
Expand Down