Merge branch 'main' into distro-ipxe
This commit is contained in:
@@ -51,6 +51,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Fixed a bug where profile tags were erroneously overridden by empty node
|
||||
values. #884
|
||||
- Fixed bug where tags from profiles weren't rendered #967
|
||||
- Fixed a bug when using `wwctl container import --force` to replace an existing container
|
||||
will generate an error #474
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -119,6 +121,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
binaries not provided by warewulf
|
||||
- use distrubtion ipxe binaries in the rpm
|
||||
- Allow absolute iPXE paths in warewulf.conf
|
||||
- Support importing containers with symlinked `/bin/sh` #797
|
||||
- Don't panic on malformed passwd #527
|
||||
|
||||
## [4.4.0] 2023-01-18
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package imprt
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
import (
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
baseCmd = &cobra.Command{
|
||||
@@ -19,6 +22,11 @@ Imported containers are used to create bootable VNFS images.`,
|
||||
Example: "wwctl container import docker://ghcr.io/hpcng/warewulf-rockylinux:8 rockylinux-8",
|
||||
RunE: CobraRunE,
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
if SetForce && SetUpdate {
|
||||
wwlog.Warn("Both --force and --update flags are set, will ignore --update flag")
|
||||
}
|
||||
},
|
||||
}
|
||||
SetForce bool
|
||||
SetUpdate bool
|
||||
|
||||
@@ -175,21 +175,23 @@ func ContainerImport(cip *wwapiv1.ContainerImportParameter) (containerName strin
|
||||
containerName = cip.Name
|
||||
fullPath := container.SourceDir(cip.Name)
|
||||
|
||||
// container already exists and should be removed first
|
||||
if util.IsDir(fullPath) && cip.Force {
|
||||
wwlog.Info("Overwriting existing VNFS")
|
||||
err = os.RemoveAll(fullPath)
|
||||
if err != nil {
|
||||
wwlog.ErrorExc(err, "")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if util.IsDir(fullPath) {
|
||||
if cip.Force {
|
||||
wwlog.Info("Overwriting existing VNFS")
|
||||
err = os.RemoveAll(fullPath)
|
||||
if err != nil {
|
||||
wwlog.ErrorExc(err, "")
|
||||
return
|
||||
}
|
||||
} else if cip.Update {
|
||||
wwlog.Info("Updating existing VNFS")
|
||||
} else {
|
||||
if !cip.Update {
|
||||
err = fmt.Errorf("VNFS Name exists, specify --force, --update, or choose a different name: %s", cip.Name)
|
||||
wwlog.Error(err.Error())
|
||||
return
|
||||
}
|
||||
wwlog.Info("Updating existing VNFS")
|
||||
} else if strings.HasPrefix(cip.Source, "docker://") || strings.HasPrefix(cip.Source, "docker-daemon://") ||
|
||||
strings.HasPrefix(cip.Source, "file://") || util.IsFile(cip.Source) {
|
||||
var sCtx *types.SystemContext
|
||||
@@ -238,12 +240,14 @@ func ContainerImport(cip *wwapiv1.ContainerImportParameter) (containerName strin
|
||||
}
|
||||
}
|
||||
|
||||
wwlog.Info("Building container: %s", cip.Name)
|
||||
err = container.Build(cip.Name, true)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not build container %s: %s", cip.Name, err.Error())
|
||||
wwlog.Error(err.Error())
|
||||
return
|
||||
if cip.Build {
|
||||
wwlog.Info("Building container: %s", cip.Name)
|
||||
err = container.Build(cip.Name, true)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not build container %s: %s", cip.Name, err.Error())
|
||||
wwlog.Error(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if cip.Default {
|
||||
|
||||
@@ -113,8 +113,8 @@ func (db syncDB) checkConflicts() error {
|
||||
for nameInHost, hostIds := range db {
|
||||
if hostIds.HostID == containerIds.ContainerID {
|
||||
errorMsg := fmt.Sprintf("id(%v) collision: host(%s) container(%s)", containerIds.ContainerID, nameInHost, nameInContainer)
|
||||
wwlog.Error(errorMsg)
|
||||
wwlog.Error("add %s to host to resolve conflict", nameInContainer)
|
||||
wwlog.Warn(errorMsg)
|
||||
wwlog.Warn("add %s to host to resolve conflict", nameInContainer)
|
||||
return errors.New(errorMsg)
|
||||
}
|
||||
}
|
||||
@@ -167,7 +167,10 @@ func (db syncDB) read(fileName string, fromContainer bool) error {
|
||||
for fileScanner.Scan() {
|
||||
line := fileScanner.Text()
|
||||
fields := strings.Split(line, ":")
|
||||
|
||||
if len(fields) != 7 {
|
||||
wwlog.Debug("malformed line in passwd: %s", line)
|
||||
continue
|
||||
}
|
||||
name := fields[0]
|
||||
if name == "" {
|
||||
continue
|
||||
|
||||
@@ -258,3 +258,13 @@ func Test_differ(t *testing.T) {
|
||||
assert.False(t, entry.match())
|
||||
assert.True(t, entry.differ())
|
||||
}
|
||||
|
||||
func Test_malformed_passwd(t *testing.T) {
|
||||
hostInput := `"testuser1:x:1001:1001::/home/testuser:/bin/bash"
|
||||
asdf`
|
||||
hostFileName := writeTempFile(t, hostInput)
|
||||
defer os.Remove(hostFileName)
|
||||
db := make(syncDB)
|
||||
err := db.readFromHost(hostFileName)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -40,7 +40,10 @@ defaultnode:
|
||||
netmask: 255.255.255.0
|
||||
onboot: true`
|
||||
|
||||
func init() {
|
||||
/*
|
||||
Creates a new nodeDb object from the on-disk configuration
|
||||
*/
|
||||
func New() (NodeYaml, error) {
|
||||
conf := warewulfconf.Get()
|
||||
if ConfigFile == "" {
|
||||
ConfigFile = path.Join(conf.Paths.Sysconfdir, "warewulf/nodes.conf")
|
||||
@@ -48,12 +51,6 @@ func init() {
|
||||
if DefaultConfig == "" {
|
||||
DefaultConfig = path.Join(conf.Paths.Datadir, "warewulf/defaults.conf")
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Creates a new nodeDb object from the on-disk configuration
|
||||
*/
|
||||
func New() (NodeYaml, error) {
|
||||
wwlog.Verbose("Opening node configuration file: %s", ConfigFile)
|
||||
data, err := os.ReadFile(ConfigFile)
|
||||
if err != nil {
|
||||
|
||||
@@ -177,7 +177,7 @@ func IsFile(path string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if stat, err := os.Stat(path); err == nil && !stat.IsDir() {
|
||||
if stat, err := os.Lstat(path); err == nil && !stat.IsDir() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -35,6 +35,8 @@ Welcome to the Warewulf User Guide!
|
||||
EL8 (Rocky Linux and RHEL) <quickstart/el8>
|
||||
EL9 (Rocky Linux and RHEL) <quickstart/el9>
|
||||
openSUSE Leap and SLES 15 <quickstart/suse15>
|
||||
Debian 12 <quickstart/debian12>
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
210
userdocs/quickstart/debian12.rst
Normal file
210
userdocs/quickstart/debian12.rst
Normal file
@@ -0,0 +1,210 @@
|
||||
=====================================
|
||||
Debian 12 Quickstart
|
||||
=====================================
|
||||
|
||||
|
||||
Install the basic services
|
||||
==========================
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt install firewalld nfs-kernel-server tftpd-hpa isc-dhcp-server
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
If you get an error message concerning *isc-dhcp-server.service* you
|
||||
probably need to configure the network intarface that isc-dhcp-server
|
||||
will listen to. Run ``sudo dpkg-reconfigure isc-dhcp-server`` and enter
|
||||
the name of your cluster's private network interface (e.g. enp2s0). After that, you might also need to run ``sudo systemctl enable isc-dhcp-server``.
|
||||
|
||||
|
||||
|
||||
Install Warewulf and dependencies
|
||||
=================================
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt install build-essential curl unzip
|
||||
|
||||
sudo apt install git golang libnfs-utils libgpgme-dev libassuan-dev
|
||||
|
||||
|
||||
mkdir ~/git
|
||||
cd ~/git
|
||||
git clone https://github.com/hpcng/warewulf.git
|
||||
cd warewulf
|
||||
git checkout main # or switch to a tag like 'v4.4.0'
|
||||
make all && sudo make install
|
||||
|
||||
|
||||
|
||||
Configure firewalld
|
||||
===================
|
||||
|
||||
Restart firewalld to register the added service file, add the service
|
||||
to the default zone, and reload.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo systemctl restart firewalld
|
||||
sudo firewall-cmd --permanent --add-service warewulf
|
||||
sudo firewall-cmd --permanent --add-service nfs
|
||||
sudo firewall-cmd --permanent --add-service tftp
|
||||
sudo firewall-cmd --reload
|
||||
|
||||
Configure the controller
|
||||
========================
|
||||
|
||||
Edit the file ``/etc/warewulf/warewulf.conf`` and ensure that you've
|
||||
set the appropriate configuration parameters. Here are some of the
|
||||
defaults for reference assuming that ``192.168.200.1`` is the IP
|
||||
address of your cluster's private network interface:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
WW_INTERNAL: 43
|
||||
ipaddr: 192.168.200.1
|
||||
netmask: 255.255.255.0
|
||||
network: 192.168.200.0
|
||||
warewulf:
|
||||
port: 9873
|
||||
secure: false
|
||||
update interval: 60
|
||||
autobuild overlays: true
|
||||
host overlay: true
|
||||
syslog: false
|
||||
dhcp:
|
||||
enabled: true
|
||||
range start: 192.168.200.50
|
||||
range end: 192.168.200.99
|
||||
systemd name: isc-dhcp-server
|
||||
tftp:
|
||||
enabled: true
|
||||
systemd name: tftpd-hpa
|
||||
nfs:
|
||||
enabled: true
|
||||
export paths:
|
||||
- path: /home
|
||||
export options: rw,sync
|
||||
mount options: defaults
|
||||
mount: true
|
||||
- path: /opt
|
||||
export options: ro,sync,no_root_squash
|
||||
mount options: defaults
|
||||
mount: false
|
||||
systemd name: nfs-server
|
||||
|
||||
.. note::
|
||||
|
||||
The DHCP range ends at ``192.168.200.99`` and as you will see
|
||||
below, the first node static IP address (post boot) is configured
|
||||
to ``192.168.200.100``.
|
||||
|
||||
Start and enable the Warewulf service
|
||||
=====================================
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Start and enable the warewulfd service
|
||||
sudo systemctl enable --now warewulfd
|
||||
|
||||
Configure system services automatically
|
||||
=======================================
|
||||
|
||||
There are a number of services and configurations that Warewulf relies
|
||||
on to operate. If you wish to configure all services, you can do so
|
||||
individually (omitting the ``--all``) will print a help and usage
|
||||
instructions.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo wwctl configure --all
|
||||
|
||||
.. note::
|
||||
|
||||
If you just installed the system fresh and have SELinux enforcing,
|
||||
you may need to reboot the system at this stage to properly set the
|
||||
contexts of the TFTP contents. After rebooting, you might also need
|
||||
to run ``$ sudo restorecon -Rv /var/lib/tftpboot/`` if there are
|
||||
errors with TFTP still.
|
||||
|
||||
Pull and build the VNFS container (including the kernel)
|
||||
========================================================
|
||||
|
||||
This will pull a basic VNFS container from Docker Hub and import the
|
||||
default running kernel from the controller node and set both in the
|
||||
"default" node profile.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
wwctl container import docker://ghcr.io/hpcng/warewulf-debian:12.0 debian-12.0
|
||||
|
||||
|
||||
Set up the default node profile
|
||||
===============================
|
||||
|
||||
Node configurations can be set via node profiles. Each node by default
|
||||
is configured to be part of the ``default`` node profile, so any
|
||||
changes you make to that profile will affect all nodes.
|
||||
|
||||
The following command will set the container we just imported above to
|
||||
the ``default`` node profile:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo wwctl profile set --yes --container debian-12.0 "default"
|
||||
|
||||
|
||||
Next we set some default networking configurations for the first
|
||||
ethernet device. On modern Linux distributions, the name of the device
|
||||
is not critical, as it will be setup according to the HW
|
||||
address. Because all nodes will share the netmask and gateway
|
||||
configuration, we can set them in the default profile as follows:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo wwctl profile set --yes --netdev eth0 --netmask 255.255.255.0 --gateway 192.168.200.1 "default"
|
||||
|
||||
Once those configurations have been set, you can view the changes by
|
||||
listing the profiles as follows:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo wwctl profile list -a
|
||||
|
||||
Add a node
|
||||
==========
|
||||
|
||||
Adding nodes can be done while setting configurations in one
|
||||
command. Here we are setting the IP address of ``eth0`` and setting
|
||||
this node to be discoverable, which will then automatically have the
|
||||
HW address added to the configuration as the node boots.
|
||||
|
||||
Node names must be unique. If you have node groups and/or multiple
|
||||
clusters, designate them using dot notation.
|
||||
|
||||
Note that the full node configuration comes from both cascading
|
||||
profiles and node configurations which always supersede profile
|
||||
configurations.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo wwctl node add n0000.cluster --ipaddr 192.168.200.100 --discoverable true
|
||||
|
||||
At this point you can view the basic configuration of this node by
|
||||
typing the following:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo wwctl node list -a n0000.cluster
|
||||
|
||||
To make node changes effective, it is a good practice to update warewulf
|
||||
overlays with the following command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo wwctl overlay build
|
||||
|
||||
Now, turn on your compute node and watch it boot!
|
||||
Reference in New Issue
Block a user