Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@

ifcfg_to_ip() {
local ip
local v="${2}",
local interface="$1"
local conf_path="/etc/cmdline.d/40-agama-network.conf"
set --
while [ -n "$v" ]; do
set -- "$@" "${v%%,*}"
v=${v#*,}
done
if [ -n "$2" ]; then
local v="${2}",
local interface="$1"
set --
while [ -n "$v" ]; do
set -- "$@" "${v%%,*}"
v=${v#*,}
done
else
local interface="*"
fi

### See https://en.opensuse.org/SDB:Linuxrc#Network_Config
# ifcfg=<interface_spec>=[try,]dhcp*,[rfc2132,]OPTION1=value1,OPTION2=value2...
Expand Down Expand Up @@ -83,6 +87,24 @@ ifcfg_to_ip() {
return 0
}

parse_hostname() {
local hostname

hostname=$(getarg hostname=)

if [[ -n $hostname ]]; then
echo "${hostname}" >/etc/hostname
fi

if ! getargbool 1 SetHostname=; then
mkdir -p /run/NetworkManager/conf.d
echo '[main]' >/run/NetworkManager/conf.d/10-agama-hostname.conf
echo 'hostname-mode=none' >>/run/NetworkManager/conf.d/10-agama-hostname.conf
fi

return 0
}

translate_ifcfg() {
local i
local vlan
Expand Down Expand Up @@ -121,3 +143,4 @@ translate_ifcfg() {
}

translate_ifcfg
parse_hostname
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ installkernel() {
install() {
inst_hook cmdline 99 "$moddir/agama-cmdline-conf.sh"
inst_hook cmdline 99 "$moddir/agama-network-compat.sh"
inst_hook pre-pivot 99 "$moddir/save-agama-conf.sh"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#! /bin/sh

[ -e /dracut-state.sh ] && . /dracut-state.sh

. /lib/dracut-lib.sh

if [ -e /etc/hostname ]; then
cp /etc/hostname "$NEWROOT/etc/hostname"
fi
9 changes: 9 additions & 0 deletions live/src/agama-installer.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
-------------------------------------------------------------------
Wed Mar 12 17:17:08 UTC 2025 - Knut Anderssen <[email protected]>

- (gh#agama-project/agama#2142)
- Allow to set the static hostname using the hostname kernel
cmdline argument.
- Allow to disable the set of the hostname via DHCP using the
SetHostname kernel cmdline argument.

-------------------------------------------------------------------
Tue Mar 11 16:29:40 UTC 2025 - Ladislav Slezák <[email protected]>

Expand Down
3 changes: 3 additions & 0 deletions rust/agama-lib/share/examples/profile.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ local memory = agama.findByID(agama.lshw, 'memory').size;
}
]
},
hostname: {
static: 'agama',
},
network: {
connections: [
{
Expand Down
35 changes: 33 additions & 2 deletions rust/agama-lib/share/profile.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,20 @@
}
}
},
"hostname": {
"title": "Hostname settings",
"type": "object",
"properties": {
"static": {
"title": "System static hostname.",
"type": "string"
},
"transient": {
"title": "System transient hostname.",
"type": "string"
}
}
},
"software": {
"title": "Software settings",
"type": "object",
Expand Down Expand Up @@ -334,13 +348,30 @@
"items": {
"title": "List of EAP methods used",
"type": "string",
"enum": ["leap", "md5", "tls", "peap", "ttls", "pwd", "fast"]
"enum": [
"leap",
"md5",
"tls",
"peap",
"ttls",
"pwd",
"fast"
]
}
},
"phase2Auth": {
"title": "Phase 2 inner auth method",
"type": "string",
"enum": ["pap", "chap", "mschap", "mschapv2", "gtc", "otp", "md5", "tls"]
"enum": [
"pap",
"chap",
"mschap",
"mschapv2",
"gtc",
"otp",
"md5",
"tls"
]
},
"identity": {
"title": "Identity string, often for example the user's login name",
Expand Down
26 changes: 26 additions & 0 deletions rust/agama-lib/src/hostname.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) [2025] SUSE LLC
//
// All Rights Reserved.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, contact SUSE LLC.
//
// To contact SUSE LLC about this file by physical or electronic mail, you may
// find current contact information at www.suse.com.

//! Implements support for handling the hostname settings

pub mod client;
pub mod http_client;
pub mod model;
pub mod store;
75 changes: 75 additions & 0 deletions rust/agama-lib/src/hostname/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright (c) [2025] SUSE LLC
//
// All Rights Reserved.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, contact SUSE LLC.
//
// To contact SUSE LLC about this file by physical or electronic mail, you may
// find current contact information at www.suse.com.

//! Implements a client to access Hostnamed D-Bus API related to hostname management.

use crate::{error::ServiceError, hostname::model::HostnameSettings, proxies::Hostname1Proxy};

/// Client to connect to org.freedesktop.hostname1 DBUS API on the system bus for Hostname management.
#[derive(Clone)]
pub struct HostnameClient<'a> {
hostname_proxy: Hostname1Proxy<'a>,
}

impl<'a> HostnameClient<'a> {
pub async fn new() -> Result<HostnameClient<'a>, ServiceError> {
let connection = zbus::Connection::system().await?;
let hostname_proxy = Hostname1Proxy::new(&connection).await?;

Ok(Self { hostname_proxy })
}

pub async fn get_config(&self) -> Result<HostnameSettings, ServiceError> {
let hostname = self.hostname_proxy.hostname().await?;
let static_hostname = self.hostname_proxy.static_hostname().await?;

let settings = HostnameSettings {
hostname: Some(hostname),
static_hostname: Some(static_hostname),
..Default::default()
};

Ok(settings)
}

pub async fn set_config(&self, config: &HostnameSettings) -> Result<(), ServiceError> {
let settings = self.get_config().await?;

// order is important as otherwise the transient hostname could not be set in case the
// static one is not empty
if let Some(config_static_hostname) = &config.static_hostname {
if settings.static_hostname != config.static_hostname {
self.hostname_proxy
.set_static_hostname(config_static_hostname.as_str(), false)
.await?;
}
}

if let Some(config_hostname) = &config.hostname {
if settings.hostname != config.hostname {
self.hostname_proxy
.set_hostname(config_hostname.as_str(), false)
.await?;
}
}

Ok(())
}
}
43 changes: 43 additions & 0 deletions rust/agama-lib/src/hostname/http_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) [2025] SUSE LLC
//
// All Rights Reserved.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, contact SUSE LLC.
//
// To contact SUSE LLC about this file by physical or electronic mail, you may
// find current contact information at www.suse.com.

//! Implements a client to access Agama's HTTP API related to Hostname management.

use crate::base_http_client::BaseHTTPClient;
use crate::hostname::model::HostnameSettings;
use crate::ServiceError;

pub struct HostnameHTTPClient {
client: BaseHTTPClient,
}

impl HostnameHTTPClient {
pub fn new(base: BaseHTTPClient) -> Self {
Self { client: base }
}

pub async fn get_config(&self) -> Result<HostnameSettings, ServiceError> {
self.client.get("/hostname/config").await
}

pub async fn set_config(&self, config: &HostnameSettings) -> Result<(), ServiceError> {
self.client.put_void("/hostname/config", config).await
}
}
34 changes: 34 additions & 0 deletions rust/agama-lib/src/hostname/model.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) [2025] SUSE LLC
//
// All Rights Reserved.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, contact SUSE LLC.
//
// To contact SUSE LLC about this file by physical or electronic mail, you may
// find current contact information at www.suse.com.

//! Implements a data model for Hostname configuration.

use serde::{Deserialize, Serialize};

/// Represents a Hostname
#[derive(Clone, Debug, Serialize, Deserialize, Default, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct HostnameSettings {
#[serde(rename = "transient")]
pub hostname: Option<String>,
// empty string means removing the static hostname
#[serde(rename = "static")]
pub static_hostname: Option<String>,
}
48 changes: 48 additions & 0 deletions rust/agama-lib/src/hostname/store.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) [2025] SUSE LLC
//
// All Rights Reserved.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, contact SUSE LLC.
//
// To contact SUSE LLC about this file by physical or electronic mail, you may
// find current contact information at www.suse.com.

//! Implements the store for the hostname settings.

use crate::base_http_client::BaseHTTPClient;
use crate::error::ServiceError;

use super::http_client::HostnameHTTPClient;
use super::model::HostnameSettings;

/// Loads and stores the hostname settings from/to the HTTP service.
pub struct HostnameStore {
hostname_client: HostnameHTTPClient,
}

impl HostnameStore {
pub fn new(client: BaseHTTPClient) -> Result<Self, ServiceError> {
Ok(Self {
hostname_client: HostnameHTTPClient::new(client),
})
}

pub async fn load(&self) -> Result<HostnameSettings, ServiceError> {
self.hostname_client.get_config().await
}

pub async fn store(&self, settings: &HostnameSettings) -> Result<(), ServiceError> {
self.hostname_client.set_config(settings).await
}
}
3 changes: 3 additions & 0 deletions rust/agama-lib/src/install_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
//!
//! This module implements the mechanisms to load and store the installation settings.
use crate::bootloader::model::BootloaderSettings;
use crate::hostname::model::HostnameSettings;
use crate::{
localization::LocalizationSettings, network::NetworkSettings, product::ProductSettings,
scripts::ScriptsConfig, software::SoftwareSettings, users::UserSettings,
Expand All @@ -42,6 +43,8 @@ use std::path::Path;
pub struct InstallSettings {
#[serde(default)]
pub bootloader: Option<BootloaderSettings>,
#[serde(default)]
pub hostname: Option<HostnameSettings>,
#[serde(default, flatten)]
pub user: Option<UserSettings>,
#[serde(default)]
Expand Down
Loading