Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an entry to /etc/hosts for the current hostname #1713

Merged
merged 3 commits into from
Sep 9, 2021
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
4 changes: 4 additions & 0 deletions Release.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,7 @@ version = "1.2.0"
"migrate_v1.2.0_container-registry-config-restarts.lz4",
"migrate_v1.2.0_admin-container-v0-7-2.lz4",
]
"(1.2.0, 1.2.1)" = [
"migrate_v1.2.1_etc-hosts-service.lz4",
"migrate_v1.2.1_hostname-affects-etc-hosts.lz4",
]
1 change: 1 addition & 0 deletions packages/release/hosts → packages/release/hosts.template
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
{{add_unresolvable_hostname settings.network.hostname}}
7 changes: 4 additions & 3 deletions packages/release/release.spec
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ Release: 0%{?dist}
Summary: Bottlerocket release
License: Apache-2.0 OR MIT

Source10: hosts
Source11: nsswitch.conf
Source97: release-sysctl.conf
Source98: release-systemd-system.conf
Expand All @@ -15,6 +14,7 @@ Source99: release-tmpfiles.conf
Source200: motd.template
Source201: proxy-env
Source202: hostname-env
Source203: hosts.template

Source1000: eth0.xml
Source1001: multi-user.target
Expand Down Expand Up @@ -91,7 +91,7 @@ Requires: %{_cross_os}wicked

%install
install -d %{buildroot}%{_cross_factorydir}%{_cross_sysconfdir}
install -p -m 0644 %{S:10} %{S:11} %{buildroot}%{_cross_factorydir}%{_cross_sysconfdir}
install -p -m 0644 %{S:11} %{buildroot}%{_cross_factorydir}%{_cross_sysconfdir}

install -d %{buildroot}%{_cross_factorydir}%{_cross_sysconfdir}/wicked/ifconfig
install -p -m 0644 %{S:1000} %{buildroot}%{_cross_factorydir}%{_cross_sysconfdir}/wicked/ifconfig
Expand Down Expand Up @@ -135,14 +135,14 @@ install -d %{buildroot}%{_cross_templatedir}
install -p -m 0644 %{S:200} %{buildroot}%{_cross_templatedir}/motd
install -p -m 0644 %{S:201} %{buildroot}%{_cross_templatedir}/proxy-env
install -p -m 0644 %{S:202} %{buildroot}%{_cross_templatedir}/hostname-env
install -p -m 0644 %{S:203} %{buildroot}%{_cross_templatedir}/hosts

install -d %{buildroot}%{_cross_udevrulesdir}
install -p -m 0644 %{S:1016} %{buildroot}%{_cross_udevrulesdir}/61-mount-cdrom.rules

ln -s %{_cross_unitdir}/preconfigured.target %{buildroot}%{_cross_unitdir}/default.target

%files
%{_cross_factorydir}%{_cross_sysconfdir}/hosts
%{_cross_factorydir}%{_cross_sysconfdir}/nsswitch.conf
%{_cross_factorydir}%{_cross_sysconfdir}/wicked/ifconfig/eth0.xml
%{_cross_sysctldir}/80-release.conf
Expand Down Expand Up @@ -175,6 +175,7 @@ ln -s %{_cross_unitdir}/preconfigured.target %{buildroot}%{_cross_unitdir}/defau
%{_cross_templatedir}/motd
%{_cross_templatedir}/proxy-env
%{_cross_templatedir}/hostname-env
%{_cross_templatedir}/hosts
%{_cross_udevrulesdir}/61-mount-cdrom.rules

%changelog
15 changes: 15 additions & 0 deletions sources/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions sources/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ members = [
"api/migration/migration-helpers",
"api/shibaken",

# "api/migration/migrations/vX.Y.Z/...
# (all migrations currently archived; replace this line with new ones)
webern marked this conversation as resolved.
Show resolved Hide resolved
# "api/migration/migrations/vX.Y.Z/..."
"api/migration/migrations/v1.2.1/etc-hosts-service",
"api/migration/migrations/v1.2.1/hostname-affects-etc-hosts",

"bottlerocket-release",

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "etc-hosts-service"
version = "0.1.0"
authors = ["Zac Mrowicki <[email protected]>"]
license = "Apache-2.0 OR MIT"
edition = "2018"
publish = false
# Don't rebuild crate just because of changes to README.
exclude = ["README.md"]

[dependencies]
migration-helpers = { path = "../../../migration-helpers" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#![deny(rust_2018_idioms)]

use migration_helpers::common_migrations::AddPrefixesMigration;
use migration_helpers::{migrate, Result};
use std::process;

/// We added a new setting and generator for configuring hostname
fn run() -> Result<()> {
migrate(AddPrefixesMigration(vec![
"services.hosts",
"configuration-files.hosts",
]))
}

// Returning a Result from main makes it print a Debug representation of the error, but with Snafu
// we have nice Display representations of the error, so we wrap "main" (run) and print any error.
// https://github.com/shepmaster/snafu/issues/110
fn main() {
if let Err(e) = run() {
eprintln!("{}", e);
process::exit(1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "hostname-affects-etc-hosts"
version = "0.1.0"
authors = ["Zac Mrowicki <[email protected]>"]
license = "Apache-2.0 OR MIT"
edition = "2018"
publish = false
# Don't rebuild crate just because of changes to README.
exclude = ["README.md"]

[dependencies]
migration-helpers = { path = "../../../migration-helpers" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#![deny(rust_2018_idioms)]

use migration_helpers::common_migrations::{
MetadataListReplacement, ReplaceMetadataListsMigration,
};
use migration_helpers::{migrate, Result};
use std::process;

/// We updated the 'affected-services' list metadata for 'settings.network.hostname' to include the
/// hosts "service" on upgrade, and to remove it on downgrade.
fn run() -> Result<()> {
migrate(ReplaceMetadataListsMigration(vec![
MetadataListReplacement {
setting: "settings.network.hostname",
metadata: "affected-services",
old_vals: &["hostname"],
new_vals: &["hostname", "hosts"],
},
]))
}

// Returning a Result from main makes it print a Debug representation of the error, but with Snafu
// we have nice Display representations of the error, so we wrap "main" (run) and print any error.
// https://github.com/shepmaster/snafu/issues/110
fn main() {
if let Err(e) = run() {
eprintln!("{}", e);
process::exit(1);
}
}
1 change: 1 addition & 0 deletions sources/api/schnauzer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ apiclient = { path = "../apiclient" }
base64 = "0.13"
constants = { path = "../../constants" }
bottlerocket-release = { path = "../../bottlerocket-release" }
dns-lookup = "1.0"
handlebars = "4.1"
http = "0.2"
lazy_static = "1.4"
Expand Down
134 changes: 131 additions & 3 deletions sources/api/schnauzer/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// be registered with the Handlebars library to assist in manipulating
// text at render time.

use dns_lookup::lookup_host;
use handlebars::{Context, Handlebars, Helper, Output, RenderContext, RenderError};
use lazy_static::lazy_static;
use num_cpus;
Expand All @@ -10,6 +11,7 @@ use snafu::{OptionExt, ResultExt};
use std::borrow::Borrow;
use std::collections::HashMap;
use std::convert::TryFrom;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use url::Url;

lazy_static! {
Expand Down Expand Up @@ -98,6 +100,9 @@ const KUBE_RESERVE_3_CORES: f32 = KUBE_RESERVE_2_CORES + 5.0;
const KUBE_RESERVE_4_CORES: f32 = KUBE_RESERVE_3_CORES + 5.0;
const KUBE_RESERVE_ADDITIONAL: f32 = 2.5;

const IPV4_LOCALHOST: IpAddr = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
const IPV6_LOCALHOST: IpAddr = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));

/// Potential errors during helper execution
mod error {
use handlebars::RenderError;
Expand Down Expand Up @@ -869,6 +874,77 @@ pub fn kube_reserve_cpu(
Ok(())
}

/// Attempts to resolve the current hostname in DNS. If unsuccessful, returns an entry formatted
/// for `/etc/hosts` that aliases the hostname to both the IPV4/6 localhost addresses.
pub fn add_unresolvable_hostname(
helper: &Helper<'_, '_>,
_: &Handlebars,
_: &Context,
renderctx: &mut RenderContext<'_, '_>,
out: &mut dyn Output,
) -> Result<(), RenderError> {
// To give context to our errors, get the template name, if available.
trace!("Starting base64_decode helper");
let template_name = template_name(renderctx);
trace!("Template name: {}", &template_name);

// Check number of parameters, must be exactly one
trace!("Number of params: {}", helper.params().len());
check_param_count(helper, template_name, 1)?;

// Get the resolved key out of the template (param(0)). value() returns
// a serde_json::Value
let hostname_value = helper
.param(0)
.map(|v| v.value())
.context(error::Internal {
msg: "Found no params after confirming there is one param",
})?;
trace!("Hostname value from template: {}", hostname_value);

// Create an &str from the serde_json::Value
let hostname_str = hostname_value
.as_str()
.context(error::InvalidTemplateValue {
expected: "string",
value: hostname_value.to_owned(),
template: template_name.to_owned(),
})?;
trace!("Hostname string from template: {}", hostname_str);

// Attempt to resolve the hostname
let hostname_resolveable = match lookup_host(hostname_str) {
Ok(ip_list) => {
// If the list of IPs is empty or resolves to localhost, consider the hostname
// unresolvable
let resolves_to_localhost = ip_list
.iter()
.any(|ip| ip == &IPV4_LOCALHOST || ip == &IPV6_LOCALHOST);
if ip_list.is_empty() || resolves_to_localhost {
false
} else {
true
}
}
Err(e) => {
trace!("DNS hostname lookup failed: {},", e);
false
}
};

// Only write an entry to the template if the hostname is unresolvable
if !hostname_resolveable {
let ipv4_entry = format!("{} {}", IPV4_LOCALHOST, hostname_str);
let ipv6_entry = format!("{} {}", IPV6_LOCALHOST, hostname_str);
let entries = format!("{}\n{}", ipv4_entry, ipv6_entry);
bcressey marked this conversation as resolved.
Show resolved Hide resolved

out.write(&entries).context(error::TemplateWrite {
template: template_name.to_owned(),
})?;
}
Ok(())
}

// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^=
// helpers to the helpers

Expand Down Expand Up @@ -935,8 +1011,9 @@ fn pause_registry<S: AsRef<str>>(region: S) -> String {
}

/// Calculates and returns the amount of CPU to reserve
fn kube_cpu_helper(num_cores: usize) -> Result<String, TemplateHelperError>{
let num_cores = u16::try_from(num_cores).context(error::ConvertUsizeToU16 { number: num_cores })?;
fn kube_cpu_helper(num_cores: usize) -> Result<String, TemplateHelperError> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a rustfmt change

let num_cores =
u16::try_from(num_cores).context(error::ConvertUsizeToU16 { number: num_cores })?;
let millicores_unit = "m";
let cpu_to_reserve = match num_cores {
0 => 0.0,
Expand All @@ -949,7 +1026,11 @@ fn kube_cpu_helper(num_cores: usize) -> Result<String, TemplateHelperError>{
KUBE_RESERVE_4_CORES + ((num_cores - 4.0) * KUBE_RESERVE_ADDITIONAL)
}
};
Ok(format!("{}{}", cpu_to_reserve.floor().to_string(), millicores_unit))
Ok(format!(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here - thanks rustfmt

"{}{}",
cpu_to_reserve.floor().to_string(),
millicores_unit
))
}

// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^=
Expand Down Expand Up @@ -1607,3 +1688,50 @@ mod test_kube_cpu_helper {
}
}
}

#[cfg(test)]
mod test_add_unresolvable_hostname {
use super::*;
use handlebars::RenderError;
use serde::Serialize;
use serde_json::json;

// A thin wrapper around the handlebars render_template method that includes
// setup and registration of helpers
fn setup_and_render_template<T>(tmpl: &str, data: &T) -> Result<String, RenderError>
where
T: Serialize,
{
let mut registry = Handlebars::new();
registry.register_helper(
"add_unresolvable_hostname",
Box::new(add_unresolvable_hostname),
);

registry.render_template(tmpl, data)
}

#[test]
fn resolves_to_localhost_renders_entries() {
let result = setup_and_render_template(
"{{add_unresolvable_hostname name}}",
&json!({"name": "localhost"}),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this test should always work on every system?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it should? I'm willing to be told otherwise though.

)
.unwrap();
assert_eq!(
result,
"127.0.0.1 localhost
::1 localhost"
)
}

#[test]
fn resolvable_hostname_renders_nothing() {
let result = setup_and_render_template(
"{{add_unresolvable_hostname name}}",
&json!({"name": "amazon.com"}),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this unresolvable by DNS? Will it always be unresolvable? Would something completely invalid be better? not*a*valid*hostname?

Copy link
Contributor Author

@zmrow zmrow Aug 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The helper only renders if the name is unresolvable or resolves to 127.0.0.1 or ::1. I realize that amazon.com isn't a realistic hostname, but it should resolve mostly anywhere and that's the behavior I was after.

)
.unwrap();
assert_eq!(result, "")
}
}
5 changes: 5 additions & 0 deletions sources/api/schnauzer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ pub fn build_template_registry() -> Result<handlebars::Handlebars<'static>> {
// but isn't provided in the data given to the renderer
template_registry.set_strict_mode(true);

// Prefer snake case for helper names (we accidentally created a few with kabob case)
template_registry.register_helper("base64_decode", Box::new(helpers::base64_decode));
template_registry.register_helper("join_map", Box::new(helpers::join_map));
template_registry.register_helper("default", Box::new(helpers::default));
Expand All @@ -131,6 +132,10 @@ pub fn build_template_registry() -> Result<handlebars::Handlebars<'static>> {
"kube_reserve_memory",
Box::new(helpers::kube_reserve_memory),
);
template_registry.register_helper(
"add_unresolvable_hostname",
webern marked this conversation as resolved.
Show resolved Hide resolved
Box::new(helpers::add_unresolvable_hostname),
);

Ok(template_registry)
}
Expand Down
Loading