Skip to content

Commit

Permalink
feat: adds custom datasource for ubuntu 22.04 (#1255)
Browse files Browse the repository at this point in the history
  • Loading branch information
faiq authored Jan 30, 2025
1 parent 89bbd8d commit aa0a7ae
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ jobs:
# we use terraform to provision *test* infrastructure that is deleted
VALIDATE_TERRAFORM_TFLINT: false
VALIDATE_ALL_CODEBASE: ${{ github.event_name == 'pull_request' }}
VALIDATE_PYTHON_ISORT: false
VALIDATE_PYTHON: false
golangci-lint:
runs-on: ubuntu-22.04
steps:
Expand Down
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 ansible/roles/providers/tasks/aws.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,21 @@
state: started
enabled: yes
when: ansible_distribution == "Ubuntu"

- 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 ansible/roles/providers/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@
when: packer_builder_type and packer_builder_type != ""

- include_tasks: vmware-redhat.yaml
when:
when:
- packer_builder_type is search('vmware') or packer_builder_type is search('vsphere')
- ansible_os_family == "RedHat"

0 comments on commit aa0a7ae

Please sign in to comment.