Skip to content
This repository has been archived by the owner on Oct 12, 2023. It is now read-only.

Commit

Permalink
Runtime: implement Bind runtime as DNS Server (#1778)
Browse files Browse the repository at this point in the history
  • Loading branch information
jerrychenhf authored Aug 16, 2023
1 parent aa167fb commit e767abe
Show file tree
Hide file tree
Showing 17 changed files with 309 additions and 6 deletions.
9 changes: 8 additions & 1 deletion python/cloudtik/core/_private/runtime_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
BUILT_IN_RUNTIME_MYSQL = "mysql"
BUILT_IN_RUNTIME_POSTGRES = "postgres"
BUILT_IN_RUNTIME_DNSMASQ = "dnsmasq"
BUILT_IN_RUNTIME_BIND = "bind"

DEFAULT_RUNTIMES = [BUILT_IN_RUNTIME_PROMETHEUS, BUILT_IN_RUNTIME_NODE_EXPORTER, BUILT_IN_RUNTIME_SPARK]

Expand Down Expand Up @@ -145,6 +146,11 @@ def _import_dnsmasq():
return DnsmasqRuntime


def _import_bind():
from cloudtik.runtime.bind.runtime import BindRuntime
return BindRuntime


_RUNTIMES = {
BUILT_IN_RUNTIME_AI: _import_ai,
BUILT_IN_RUNTIME_SPARK: _import_spark,
Expand All @@ -166,7 +172,8 @@ def _import_dnsmasq():
BUILT_IN_RUNTIME_GRAFANA: _import_grafana,
BUILT_IN_RUNTIME_MYSQL: _import_mysql,
BUILT_IN_RUNTIME_POSTGRES: _import_postgres,
BUILT_IN_RUNTIME_DNSMASQ: _import_dnsmasq(),
BUILT_IN_RUNTIME_DNSMASQ: _import_dnsmasq,
BUILT_IN_RUNTIME_BIND: _import_bind,
}


Expand Down
Empty file.
6 changes: 6 additions & 0 deletions python/cloudtik/runtime/bind/conf/named
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#
# run resolvconf?
RESOLVCONF=no

# startup options for the server
OPTIONS="-u bind -c {%bind.home%}/conf/named.conf"
11 changes: 11 additions & 0 deletions python/cloudtik/runtime/bind/conf/named.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// This is the primary configuration file for the BIND DNS server named.
//
// Please read /usr/share/doc/bind9/README.Debian.gz for information on the
// structure of BIND configuration files in Debian, *BEFORE* you customize
// this configuration file.
//
// If you are just adding zones, please do that in /etc/bind/named.conf.local

include "{%bind.home%}/conf/named.conf.options";
include "/etc/bind/named.conf.local";
include "/etc/bind/named.conf.default-zones";
5 changes: 5 additions & 0 deletions python/cloudtik/runtime/bind/conf/named.conf.consul
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
zone "cloudtik" IN {
type forward;
forward only;
forwarders { 127.0.0.1 port 8600; };
};
9 changes: 9 additions & 0 deletions python/cloudtik/runtime/bind/conf/named.conf.options
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
options {
listen-on port {%listen.port%} { 127.0.0.1; };
listen-on port {%listen.port%} { {%listen.address%}; };

directory "{%data.dir%}";

dnssec-enable no;
dnssec-validation no;
};
25 changes: 25 additions & 0 deletions python/cloudtik/runtime/bind/config/commands.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Custom commands that will be run on the head node after common setup.
head_setup_commands:
- cloudtik runtime install bind --head
- cloudtik runtime configure bind --head

# Custom commands that will be run on worker nodes after common setup.
worker_setup_commands:
- cloudtik runtime install bind
- cloudtik runtime configure bind

# Command to start on the head node. You don't need to change this.
head_start_commands:
- cloudtik runtime services bind start --head

# Command to start on worker nodes. You don't need to change this.
worker_start_commands:
- cloudtik runtime services bind start

# Command to start on the head node. You don't need to change this.
head_stop_commands:
- cloudtik runtime services bind stop --head

# Command to start on worker nodes. You don't need to change this.
worker_stop_commands:
- cloudtik runtime services bind stop
1 change: 1 addition & 0 deletions python/cloudtik/runtime/bind/config/defaults.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Configuration defaults
33 changes: 33 additions & 0 deletions python/cloudtik/runtime/bind/runtime.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import logging
from typing import Any, Dict

from cloudtik.core.node_provider import NodeProvider
from cloudtik.runtime.common.runtime_base import RuntimeBase
from cloudtik.runtime.bind.utils import _get_runtime_processes, \
_get_runtime_services, _with_runtime_environment_variables

logger = logging.getLogger(__name__)


class BindRuntime(RuntimeBase):
"""Implementation for Bind Runtime for a DNS Server
which resolves domain names for both local and upstream"""

def __init__(self, runtime_config: Dict[str, Any]) -> None:
super().__init__(runtime_config)

def with_environment_variables(
self, config: Dict[str, Any], provider: NodeProvider,
node_id: str) -> Dict[str, Any]:
"""Export necessary runtime environment variables for running node commands.
For example: {"ENV_NAME": value}
"""
return _with_runtime_environment_variables(
self.runtime_config, config=config)

def get_runtime_services(self, cluster_name: str):
return _get_runtime_services(self.runtime_config, cluster_name)

@staticmethod
def get_processes():
return _get_runtime_processes()
82 changes: 82 additions & 0 deletions python/cloudtik/runtime/bind/scripts/configure.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/bin/bash

# Current bin directory
BIN_DIR=`dirname "$0"`
ROOT_DIR="$(dirname "$(dirname "$BIN_DIR")")"

args=$(getopt -a -o h:: -l head:: -- "$@")
eval set -- "${args}"

USER_HOME=/home/$(whoami)
RUNTIME_PATH=$USER_HOME/runtime
BIND_HOME=$RUNTIME_PATH/bind

# Util functions
. "$ROOT_DIR"/common/scripts/util-functions.sh

function prepare_base_conf() {
local source_dir=$(dirname "${BIN_DIR}")/conf
output_dir=/tmp/bind/conf
rm -rf $output_dir
mkdir -p $output_dir
cp -r $source_dir/* $output_dir
}

function check_bind_installed() {
if ! command -v named &> /dev/null
then
echo "Bind is not installed for named command is not available."
exit 1
fi
}

function configure_data_dir() {
local data_disk_dir=$(get_first_data_disk_dir)
if [ -z "$data_disk_dir" ]; then
data_dir="${BIND_HOME}/data"
else
data_dir="$data_disk_dir/bind/data"
fi

mkdir -p ${data_dir}
sed -i "s!{%data.dir%}!${data_dir}!g" ${output_dir}/named.conf.options
}

function configure_bind() {
prepare_base_conf

ETC_DEFAULT=/etc/default
sudo mkdir -p ${ETC_DEFAULT}

sed -i "s#{%bind.home%}#${BIND_HOME}#g" ${output_dir}/named
sudo cp ${output_dir}/named ${ETC_DEFAULT}/named

BIND_CONF_DIR=${BIND_HOME}/conf
mkdir -p ${BIND_CONF_DIR}

config_template_file=${output_dir}/named.conf

sed -i "s#{%bind.home%}#${BIND_HOME}#g" ${config_template_file}

sed -i "s#{%listen.address%}#${NODE_IP_ADDRESS}#g" ${output_dir}/named.conf.options
sed -i "s#{%listen.port%}#${BIND_SERVICE_PORT}#g" ${output_dir}/named.conf.options

configure_data_dir

# generate additional name server records for specific (service discovery) domain
if [ "${BIND_CONSUL_RESOLVE}" == "true" ]; then
# TODO: handle consul port other than default
cp ${output_dir}/named.conf.consul ${BIND_CONF_DIR}/named.conf.consul
echo "include \"${BIND_HOME}/conf/named.conf.consul\";" >> ${config_template_file}
fi

cp ${output_dir}/named.conf.options ${BIND_CONF_DIR}/named.conf.options
cp ${config_template_file} ${BIND_CONF_DIR}/named.conf
}

set_head_option "$@"
check_bind_installed
set_node_ip_address
configure_bind

exit 0
23 changes: 23 additions & 0 deletions python/cloudtik/runtime/bind/scripts/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash

# Current bin directory
BIN_DIR=`dirname "$0"`
ROOT_DIR="$(dirname "$(dirname "$BIN_DIR")")"

args=$(getopt -a -o h:: -l head:: -- "$@")
eval set -- "${args}"

# Util functions
. "$ROOT_DIR"/common/scripts/util-functions.sh

function install_bind() {
if ! command -v named &> /dev/null
then
sudo apt-get -qq update -y > /dev/null; \
sudo DEBIAN_FRONTEND=noninteractive apt-get install -qq -y bind9 > /dev/null
fi
}

set_head_option "$@"
install_bind
clean_install_cache
31 changes: 31 additions & 0 deletions python/cloudtik/runtime/bind/scripts/services.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/bash

# Current bin directory
BIN_DIR=`dirname "$0"`
ROOT_DIR="$(dirname "$(dirname "$BIN_DIR")")"

args=$(getopt -a -o h:: -l head:: -- "$@")
eval set -- "${args}"

# import util functions
. "$ROOT_DIR"/common/scripts/util-functions.sh

set_head_option "$@"
set_service_command "$@"

case "$SERVICE_COMMAND" in
start)
sudo service named start
;;
stop)
sudo service named stop
;;
-h|--help)
echo "Usage: $0 start|stop --head" >&2
;;
*)
echo "Usage: $0 start|stop --head" >&2
;;
esac

exit 0
70 changes: 70 additions & 0 deletions python/cloudtik/runtime/bind/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import os
from typing import Any, Dict

from cloudtik.core._private.runtime_factory import BUILT_IN_RUNTIME_BIND, BUILT_IN_RUNTIME_CONSUL
from cloudtik.core._private.service_discovery.utils import \
get_canonical_service_name, define_runtime_service, \
get_service_discovery_config
from cloudtik.core._private.utils import get_runtime_config
from cloudtik.runtime.common.service_discovery.cluster import has_runtime_in_cluster

RUNTIME_PROCESSES = [
# The first element is the substring to filter.
# The second element, if True, is to filter ps results by command name.
# The third element is the process name.
# The forth element, if node, the process should on all nodes,if head, the process should on head node.
["named", True, "DNS Server", "node"],
]

BIND_SERVICE_PORT_CONFIG_KEY = "port"

BIND_SERVICE_NAME = BUILT_IN_RUNTIME_BIND
BIND_SERVICE_PORT_DEFAULT = 53


def _get_config(runtime_config: Dict[str, Any]):
return runtime_config.get(BUILT_IN_RUNTIME_BIND, {})


def _get_service_port(bind_config: Dict[str, Any]):
return bind_config.get(
BIND_SERVICE_PORT_CONFIG_KEY, BIND_SERVICE_PORT_DEFAULT)


def _get_home_dir():
return os.path.join(
os.getenv("HOME"), "runtime", BUILT_IN_RUNTIME_BIND)


def _get_runtime_processes():
return RUNTIME_PROCESSES


def _with_runtime_environment_variables(
runtime_config, config):
runtime_envs = {}
bind_config = _get_config(runtime_config)

service_port = _get_service_port(bind_config)
runtime_envs["BIND_SERVICE_PORT"] = service_port

cluster_runtime_config = get_runtime_config(config)
if has_runtime_in_cluster(
cluster_runtime_config, BUILT_IN_RUNTIME_CONSUL):
runtime_envs["BIND_CONSUL_RESOLVE"] = True

return runtime_envs


def _get_runtime_services(
runtime_config: Dict[str, Any], cluster_name: str) -> Dict[str, Any]:
bind_config = _get_config(runtime_config)
service_discovery_config = get_service_discovery_config(bind_config)
service_name = get_canonical_service_name(
service_discovery_config, cluster_name, BIND_SERVICE_NAME)
service_port = _get_service_port(bind_config)
services = {
service_name: define_runtime_service(
service_discovery_config, service_port),
}
return services
2 changes: 1 addition & 1 deletion python/cloudtik/runtime/dnsmasq/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@


class DnsmasqRuntime(RuntimeBase):
"""Implementation for Dnsmasq Runtime for a DNS server
"""Implementation for Dnsmasq Runtime for a DNS forwarder
which resolves domain names for both local and upstream"""

def __init__(self, runtime_config: Dict[str, Any]) -> None:
Expand Down
2 changes: 1 addition & 1 deletion python/cloudtik/runtime/dnsmasq/scripts/configure.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function configure_dnsmasq() {
sudo cp ${output_dir}/dnsmasq ${ETC_DEFAULT}/dnsmasq

DNSMASQ_CONF_DIR=${DNSMASQ_HOME}/conf
DNSMASQ_CONF_INCLUDE_DIR==${DNSMASQ_CONF_DIR}/conf.d
DNSMASQ_CONF_INCLUDE_DIR=${DNSMASQ_CONF_DIR}/conf.d
mkdir -p ${DNSMASQ_CONF_INCLUDE_DIR}

config_template_file=${output_dir}/dnsmasq.conf
Expand Down
4 changes: 2 additions & 2 deletions python/cloudtik/runtime/dnsmasq/scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ eval set -- "${args}"
function install_dnsmasq() {
if ! command -v dnsmasq &> /dev/null
then
apt-get -qq update -y > /dev/null; \
sudo DEBIAN_FRONTEND=noninteractive apt-get install -qq -y dnsmasq > /dev/null
sudo apt-get -qq update -y > /dev/null; \
sudo DEBIAN_FRONTEND=noninteractive apt-get install -qq -y dnsmasq > /dev/null
fi
}

Expand Down
2 changes: 1 addition & 1 deletion python/cloudtik/runtime/dnsmasq/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# The second element, if True, is to filter ps results by command name.
# The third element is the process name.
# The forth element, if node, the process should on all nodes,if head, the process should on head node.
["dnsmasq", True, "DNS Server", "node"],
["dnsmasq", True, "DNS Forwarder", "node"],
]

DNSMASQ_SERVICE_PORT_CONFIG_KEY = "port"
Expand Down

0 comments on commit e767abe

Please sign in to comment.