Skip to content

Commit 79987c0

Browse files
committed
feat: generate iqn and nqn files
Generate deterministic IQN and NQN files based on `machine-id`. Fixes: siderolabs#10009 Signed-off-by: Noel Georgi <[email protected]>
1 parent 0cab6ed commit 79987c0

File tree

6 files changed

+248
-5
lines changed

6 files changed

+248
-5
lines changed

Dockerfile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ END
735735
COPY ./hack/cleanup.sh /toolchain/bin/cleanup.sh
736736
RUN <<END
737737
cleanup.sh /rootfs
738-
mkdir -pv /rootfs/{boot/EFI,etc/cri/conf.d/hosts,lib/firmware,usr/etc,usr/local/share,usr/share/zoneinfo/Etc,mnt,system,opt,.extra}
738+
mkdir -pv /rootfs/{boot/EFI,etc/{iscsi,nvme,cri/conf.d/hosts},lib/firmware,usr/etc,usr/local/share,usr/share/zoneinfo/Etc,mnt,system,opt,.extra}
739739
mkdir -pv /rootfs/{etc/kubernetes/manifests,etc/cni/net.d,etc/ssl/certs,usr/libexec/kubernetes,/usr/local/lib/kubelet/credentialproviders,etc/selinux/targeted/contexts/files}
740740
mkdir -pv /rootfs/opt/{containerd/bin,containerd/lib}
741741
END
@@ -750,7 +750,7 @@ COPY --chmod=0644 hack/lvm.conf /rootfs/etc/lvm/lvm.conf
750750
COPY --chmod=0644 --from=base /src/pkg/machinery/version/os-release /rootfs/etc/os-release
751751
RUN <<END
752752
ln -s /usr/share/zoneinfo/Etc/UTC /rootfs/etc/localtime
753-
touch /rootfs/etc/{extensions.yaml,resolv.conf,hosts,machine-id,cri/conf.d/cri.toml,cri/conf.d/01-registries.part,cri/conf.d/20-customization.part,cri/conf.d/base-spec.json,ssl/certs/ca-certificates,selinux/targeted/contexts/files/file_contexts}
753+
touch /rootfs/etc/{extensions.yaml,resolv.conf,hosts,machine-id,cri/conf.d/cri.toml,cri/conf.d/01-registries.part,cri/conf.d/20-customization.part,cri/conf.d/base-spec.json,ssl/certs/ca-certificates,selinux/targeted/contexts/files/file_contexts,iscsi/initiatorname.iscsi,nvme/{hostid,hostnqn}}
754754
ln -s ca-certificates /rootfs/etc/ssl/certs/ca-certificates.crt
755755
ln -s /etc/ssl /rootfs/etc/pki
756756
ln -s /etc/ssl /rootfs/usr/share/ca-certificates
@@ -812,7 +812,7 @@ END
812812
COPY ./hack/cleanup.sh /toolchain/bin/cleanup.sh
813813
RUN <<END
814814
cleanup.sh /rootfs
815-
mkdir -pv /rootfs/{boot/EFI,etc/cri/conf.d/hosts,lib/firmware,usr/etc,usr/local/share,usr/share/zoneinfo/Etc,mnt,system,opt,.extra}
815+
mkdir -pv /rootfs/{boot/EFI,etc/{iscsi,nvme,cri/conf.d/hosts},lib/firmware,usr/etc,usr/local/share,usr/share/zoneinfo/Etc,mnt,system,opt,.extra}
816816
mkdir -pv /rootfs/{etc/kubernetes/manifests,etc/cni/net.d,etc/ssl/certs,usr/libexec/kubernetes,/usr/local/lib/kubelet/credentialproviders,etc/selinux/targeted/contexts/files}
817817
mkdir -pv /rootfs/opt/{containerd/bin,containerd/lib}
818818
END
@@ -827,7 +827,7 @@ COPY --chmod=0644 hack/lvm.conf /rootfs/etc/lvm/lvm.conf
827827
COPY --chmod=0644 --from=base /src/pkg/machinery/version/os-release /rootfs/etc/os-release
828828
RUN <<END
829829
ln -s /usr/share/zoneinfo/Etc/UTC /rootfs/etc/localtime
830-
touch /rootfs/etc/{extensions.yaml,resolv.conf,hosts,machine-id,cri/conf.d/cri.toml,cri/conf.d/01-registries.part,cri/conf.d/20-customization.part,cri/conf.d/base-spec.json,ssl/certs/ca-certificates,selinux/targeted/contexts/files/file_contexts}
830+
touch /rootfs/etc/{extensions.yaml,resolv.conf,hosts,machine-id,cri/conf.d/cri.toml,cri/conf.d/01-registries.part,cri/conf.d/20-customization.part,cri/conf.d/base-spec.json,ssl/certs/ca-certificates,selinux/targeted/contexts/files/file_contexts,iscsi/initiatorname.iscsi,nvme/{hostid,hostnqn}}
831831
ln -s /etc/ssl /rootfs/etc/pki
832832
ln -s ca-certificates /rootfs/etc/ssl/certs/ca-certificates.crt
833833
ln -s /etc/ssl /rootfs/usr/share/ca-certificates

hack/release.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,24 @@ cluster:
7474
```
7575
7676
Usage of `authorization-mode` CLI argument will not support this form of customization.
77+
"""
78+
79+
[notes.iscsi-initiator-iqn]
80+
title = "iSCSI Initiator"
81+
description = """\
82+
Talos now generates `/etc/iscsi/initiatorname.iscsi` file based on the node identity which is tied to the lifecycle of the node.
83+
If using `iscsi-tools` extension, starting with Talos 1.10 would have a more deterministic IQN for the initiator node.
84+
Make sure to update any iSCSI targets to use the new initiator IQN.
85+
86+
The iqn can be read by `talosctl read /etc/iscsi/initiatorname.iscsi`
87+
"""
88+
89+
[notes.nvme-nqn]
90+
title = "NVMe NQN"
91+
description = """\
92+
Talos now generates `/etc/nvme/hostnqn` and `/etc/nvme/hostid` files based on the node identity which is tied to the lifecycle of the node.
93+
94+
The NQN can be read by `talosctl read /etc/nvme/hostnqn`
7795
"""
7896

7997
[make_deps]

internal/app/machined/pkg/controllers/cluster/node_identity.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ func (ctrl *NodeIdentityController) Run(ctx context.Context, r controller.Runtim
119119

120120
return err
121121
}); err != nil {
122-
return fmt.Errorf("error modifying resolv.conf: %w", err)
122+
return fmt.Errorf("error modifying machine-id: %w", err)
123123
}
124124

125125
if !ctrl.identityEstablished {
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
5+
package files
6+
7+
import (
8+
"context"
9+
"fmt"
10+
11+
"github.com/cosi-project/runtime/pkg/controller"
12+
"github.com/cosi-project/runtime/pkg/safe"
13+
"github.com/cosi-project/runtime/pkg/state"
14+
"github.com/siderolabs/gen/optional"
15+
"go.uber.org/zap"
16+
17+
clusteradapter "github.com/siderolabs/talos/internal/app/machined/pkg/adapters/cluster"
18+
runtimetalos "github.com/siderolabs/talos/internal/app/machined/pkg/runtime"
19+
"github.com/siderolabs/talos/pkg/machinery/constants"
20+
"github.com/siderolabs/talos/pkg/machinery/resources/cluster"
21+
"github.com/siderolabs/talos/pkg/machinery/resources/files"
22+
)
23+
24+
// IQNController creates an EtcFileSpec for the iSCSI Qualified Name (IQN) file.
25+
type IQNController struct {
26+
V1Alpha1Mode runtimetalos.Mode
27+
}
28+
29+
// Name implements controller.Controller interface.
30+
func (ctrl *IQNController) Name() string {
31+
return "files.IQNController"
32+
}
33+
34+
// Inputs implements controller.Controller interface.
35+
func (ctrl *IQNController) Inputs() []controller.Input {
36+
return []controller.Input{
37+
{
38+
Namespace: cluster.NamespaceName,
39+
Type: cluster.IdentityType,
40+
ID: optional.Some(cluster.LocalIdentity),
41+
Kind: controller.InputWeak,
42+
},
43+
}
44+
}
45+
46+
// Outputs implements controller.Controller interface.
47+
func (ctrl *IQNController) Outputs() []controller.Output {
48+
return []controller.Output{
49+
{
50+
Type: files.EtcFileSpecType,
51+
Kind: controller.OutputShared,
52+
},
53+
}
54+
}
55+
56+
// Run implements controller.Controller interface.
57+
func (ctrl *IQNController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {
58+
// Skip the controller if we're running in a container.
59+
if ctrl.V1Alpha1Mode == runtimetalos.ModeContainer {
60+
return nil
61+
}
62+
63+
for {
64+
select {
65+
case <-ctx.Done():
66+
return nil
67+
case <-r.EventCh():
68+
}
69+
70+
// get the local node identity
71+
localIdentity, err := safe.ReaderGetByID[*cluster.Identity](ctx, r, cluster.LocalIdentity)
72+
if err != nil {
73+
if state.IsNotFoundError(err) {
74+
continue
75+
}
76+
77+
return fmt.Errorf("failed to get machine-id etcfile status: %w", err)
78+
}
79+
80+
machineID, err := clusteradapter.IdentitySpec(localIdentity.TypedSpec()).ConvertMachineID()
81+
if err != nil {
82+
return fmt.Errorf("failed to convert identity to machine ID: %w", err)
83+
}
84+
85+
if err := safe.WriterModify(ctx, r, files.NewEtcFileSpec(files.NamespaceName, "iscsi/initiatorname.iscsi"),
86+
func(r *files.EtcFileSpec) error {
87+
spec := r.TypedSpec()
88+
89+
// Fri Nov 3 16:19:12 2017 -0700 is the date of the first commit in the talos repository.
90+
spec.Contents = []byte(fmt.Sprintf("InitiatorName=iqn.2017.11.dev.talos:%s\n", machineID))
91+
spec.Mode = 0o600
92+
spec.SelinuxLabel = constants.EtcSelinuxLabel
93+
94+
return nil
95+
}); err != nil {
96+
return fmt.Errorf("error modifying resource: %w", err)
97+
}
98+
}
99+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
5+
package files
6+
7+
import (
8+
"context"
9+
"fmt"
10+
11+
"github.com/cosi-project/runtime/pkg/controller"
12+
"github.com/cosi-project/runtime/pkg/safe"
13+
"github.com/cosi-project/runtime/pkg/state"
14+
"github.com/google/uuid"
15+
"github.com/siderolabs/gen/optional"
16+
"go.uber.org/zap"
17+
18+
clusteradapter "github.com/siderolabs/talos/internal/app/machined/pkg/adapters/cluster"
19+
runtimetalos "github.com/siderolabs/talos/internal/app/machined/pkg/runtime"
20+
"github.com/siderolabs/talos/pkg/machinery/constants"
21+
"github.com/siderolabs/talos/pkg/machinery/resources/cluster"
22+
"github.com/siderolabs/talos/pkg/machinery/resources/files"
23+
)
24+
25+
// NQNController creates an EtcFileSpec for the NVMe Qualified Name (NQN) and HostID file.
26+
type NQNController struct {
27+
V1Alpha1Mode runtimetalos.Mode
28+
}
29+
30+
// Name implements controller.Controller interface.
31+
func (ctrl *NQNController) Name() string {
32+
return "files.NQNController"
33+
}
34+
35+
// Inputs implements controller.Controller interface.
36+
func (ctrl *NQNController) Inputs() []controller.Input {
37+
return []controller.Input{
38+
{
39+
Namespace: cluster.NamespaceName,
40+
Type: cluster.IdentityType,
41+
ID: optional.Some(cluster.LocalIdentity),
42+
Kind: controller.InputWeak,
43+
},
44+
}
45+
}
46+
47+
// Outputs implements controller.Controller interface.
48+
func (ctrl *NQNController) Outputs() []controller.Output {
49+
return []controller.Output{
50+
{
51+
Type: files.EtcFileSpecType,
52+
Kind: controller.OutputShared,
53+
},
54+
}
55+
}
56+
57+
// Run implements controller.Controller interface.
58+
//
59+
//nolint:gocyclo
60+
func (ctrl *NQNController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {
61+
// Skip the controller if we're running in a container.
62+
if ctrl.V1Alpha1Mode == runtimetalos.ModeContainer {
63+
return nil
64+
}
65+
66+
for {
67+
select {
68+
case <-ctx.Done():
69+
return nil
70+
case <-r.EventCh():
71+
}
72+
73+
// get the local node identity
74+
localIdentity, err := safe.ReaderGetByID[*cluster.Identity](ctx, r, cluster.LocalIdentity)
75+
if err != nil {
76+
if state.IsNotFoundError(err) {
77+
continue
78+
}
79+
80+
return fmt.Errorf("failed to get machine-id etcfile status: %w", err)
81+
}
82+
83+
machineID, err := clusteradapter.IdentitySpec(localIdentity.TypedSpec()).ConvertMachineID()
84+
if err != nil {
85+
return fmt.Errorf("failed to convert identity to machine ID: %w", err)
86+
}
87+
88+
hostID, err := uuid.FromBytes(machineID[:16])
89+
if err != nil {
90+
return fmt.Errorf("failed to convert machine-id to UUID: %w", err)
91+
}
92+
93+
if err := safe.WriterModify(ctx, r, files.NewEtcFileSpec(files.NamespaceName, "nvme/hostid"),
94+
func(r *files.EtcFileSpec) error {
95+
spec := r.TypedSpec()
96+
97+
spec.Contents = []byte(hostID.String())
98+
spec.Mode = 0o600
99+
spec.SelinuxLabel = constants.EtcSelinuxLabel
100+
101+
return nil
102+
}); err != nil {
103+
return fmt.Errorf("error modifying resource: %w", err)
104+
}
105+
106+
if err := safe.WriterModify(ctx, r, files.NewEtcFileSpec(files.NamespaceName, "nvme/hostnqn"),
107+
func(r *files.EtcFileSpec) error {
108+
spec := r.TypedSpec()
109+
110+
// Fri Nov 3 16:19:12 2017 -0700 is the date of the first commit in the talos repository.
111+
spec.Contents = []byte(fmt.Sprintf("nqn.2017.11.dev.talos:uuid:%s", hostID.String()))
112+
spec.Mode = 0o600
113+
spec.SelinuxLabel = constants.EtcSelinuxLabel
114+
115+
return nil
116+
}); err != nil {
117+
return fmt.Errorf("error modifying resource: %w", err)
118+
}
119+
}
120+
}

internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error
152152
EtcPath: "/etc",
153153
ShadowPath: constants.SystemEtcPath,
154154
},
155+
&files.IQNController{
156+
V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),
157+
},
158+
&files.NQNController{
159+
V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),
160+
},
155161
&hardware.PCIDevicesController{
156162
V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),
157163
},

0 commit comments

Comments
 (0)