diff --git a/Dockerfile b/Dockerfile index b10c71d34..8f24c5f6c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -377,9 +377,7 @@ COPY ./hack/cleanup.sh /toolchain/bin/cleanup.sh RUN cleanup.sh /rootfs COPY --chmod=0644 hack/containerd.toml /rootfs/etc/containerd/config.toml COPY --chmod=0644 hack/cri-containerd.toml /rootfs/etc/cri/containerd.toml -RUN touch /rootfs/etc/resolv.conf -RUN touch /rootfs/etc/hosts -RUN touch /rootfs/etc/os-release +RUN touch /rootfs/etc/{resolv.conf,hosts,os-release,machine-id} RUN mkdir -pv /rootfs/{boot,usr/local/share,mnt,system,opt} RUN mkdir -pv /rootfs/{etc/kubernetes/manifests,etc/cni/net.d,usr/libexec/kubernetes} RUN mkdir -pv /rootfs/opt/{containerd/bin,containerd/lib} @@ -421,9 +419,7 @@ COPY ./hack/cleanup.sh /toolchain/bin/cleanup.sh RUN cleanup.sh /rootfs COPY --chmod=0644 hack/containerd.toml /rootfs/etc/containerd/containerd.toml COPY --chmod=0644 hack/cri-containerd.toml /rootfs/etc/cri/containerd.toml -RUN touch /rootfs/etc/resolv.conf -RUN touch /rootfs/etc/hosts -RUN touch /rootfs/etc/os-release +RUN touch /rootfs/etc/{resolv.conf,hosts,os-release,machine-id} RUN mkdir -pv /rootfs/{boot,usr/local/share,mnt,system,opt} RUN mkdir -pv /rootfs/{etc/kubernetes/manifests,etc/cni/net.d,usr/libexec/kubernetes} RUN mkdir -pv /rootfs/opt/{containerd/bin,containerd/lib} diff --git a/internal/app/machined/pkg/adapters/cluster/identity.go b/internal/app/machined/pkg/adapters/cluster/identity.go index 848977920..f7b65c040 100644 --- a/internal/app/machined/pkg/adapters/cluster/identity.go +++ b/internal/app/machined/pkg/adapters/cluster/identity.go @@ -6,6 +6,7 @@ package cluster import ( "crypto/rand" + "encoding/hex" "io" "github.com/jxskiss/base62" @@ -39,3 +40,16 @@ func (a identity) Generate() error { return nil } + +// ConvertMachineID returns /etc/machine-id compatible representation. +func (a identity) ConvertMachineID() ([]byte, error) { + raw, err := base62.DecodeString(a.IdentitySpec.NodeID) + if err != nil { + return nil, err + } + + buf := make([]byte, 32) + hex.Encode(buf, raw[:16]) + + return buf, nil +} diff --git a/internal/app/machined/pkg/adapters/cluster/identity_test.go b/internal/app/machined/pkg/adapters/cluster/identity_test.go index e24225b2a..c0e289460 100644 --- a/internal/app/machined/pkg/adapters/cluster/identity_test.go +++ b/internal/app/machined/pkg/adapters/cluster/identity_test.go @@ -27,3 +27,14 @@ func TestIdentityGenerate(t *testing.T) { assert.GreaterOrEqual(t, length, 43) assert.LessOrEqual(t, length, 44) } + +func TestIdentityConvertMachineID(t *testing.T) { + spec := cluster.IdentitySpec{ + NodeID: "sou7yy34ykX3n373Zw1DXKb8zD7UnyKT6HT3QDsGH6L", + } + + machineID, err := clusteradapter.IdentitySpec(&spec).ConvertMachineID() + require.NoError(t, err) + + assert.Equal(t, "be871ac0d0dd31fa4caca753b0f3f1b2", string(machineID)) +} diff --git a/internal/app/machined/pkg/controllers/cluster/node_identity.go b/internal/app/machined/pkg/controllers/cluster/node_identity.go index d7e622f72..57cfcebd7 100644 --- a/internal/app/machined/pkg/controllers/cluster/node_identity.go +++ b/internal/app/machined/pkg/controllers/cluster/node_identity.go @@ -20,6 +20,7 @@ import ( "github.com/talos-systems/talos/internal/app/machined/pkg/runtime" "github.com/talos-systems/talos/pkg/machinery/constants" "github.com/talos-systems/talos/pkg/machinery/resources/cluster" + "github.com/talos-systems/talos/pkg/machinery/resources/files" runtimeres "github.com/talos-systems/talos/pkg/machinery/resources/runtime" "github.com/talos-systems/talos/pkg/machinery/resources/v1alpha1" ) @@ -56,6 +57,10 @@ func (ctrl *NodeIdentityController) Outputs() []controller.Output { Type: cluster.IdentityType, Kind: controller.OutputShared, }, + { + Type: files.EtcFileSpecType, + Kind: controller.OutputShared, + }, } } @@ -102,6 +107,19 @@ func (ctrl *NodeIdentityController) Run(ctx context.Context, r controller.Runtim return fmt.Errorf("error modifying resource: %w", err) } + // generate `/etc/machine-id` from node identity + if err := r.Modify(ctx, files.NewEtcFileSpec(files.NamespaceName, "machine-id"), + func(r resource.Resource) error { + var err error + + r.(*files.EtcFileSpec).TypedSpec().Contents, err = clusteradapter.IdentitySpec(&localIdentity).ConvertMachineID() + r.(*files.EtcFileSpec).TypedSpec().Mode = 0o444 + + return err + }); err != nil { + return fmt.Errorf("error modifying resolv.conf: %w", err) + } + if !ctrl.identityEstablished { logger.Info("node identity established", zap.String("node_id", localIdentity.NodeID)) diff --git a/internal/app/machined/pkg/controllers/cluster/node_identity_test.go b/internal/app/machined/pkg/controllers/cluster/node_identity_test.go index 109b59dfb..5a2475bd5 100644 --- a/internal/app/machined/pkg/controllers/cluster/node_identity_test.go +++ b/internal/app/machined/pkg/controllers/cluster/node_identity_test.go @@ -19,6 +19,7 @@ import ( v1alpha1runtime "github.com/talos-systems/talos/internal/app/machined/pkg/runtime" "github.com/talos-systems/talos/pkg/machinery/constants" "github.com/talos-systems/talos/pkg/machinery/resources/cluster" + "github.com/talos-systems/talos/pkg/machinery/resources/files" runtimeres "github.com/talos-systems/talos/pkg/machinery/resources/runtime" "github.com/talos-systems/talos/pkg/machinery/resources/v1alpha1" ) @@ -68,6 +69,12 @@ func (suite *NodeIdentitySuite) TestDefault() { return nil }), )) + + suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( + suite.assertResource(*files.NewEtcFileSpec(files.NamespaceName, "machine-id").Metadata(), func(_ resource.Resource) error { + return nil + }), + )) } func (suite *NodeIdentitySuite) TestLoad() { @@ -93,6 +100,14 @@ func (suite *NodeIdentitySuite) TestLoad() { return nil }), )) + + suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( + suite.assertResource(*files.NewEtcFileSpec(files.NamespaceName, "machine-id").Metadata(), func(r resource.Resource) error { + suite.Assert().Equal("8d2c0de2408fa2a178bad7f45d9aa8fb", string(r.(*files.EtcFileSpec).TypedSpec().Contents)) + + return nil + }), + )) } func TestNodeIdentitySuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/k8s/kubelet_service.go b/internal/app/machined/pkg/controllers/k8s/kubelet_service.go index c399a8ff4..539d5c373 100644 --- a/internal/app/machined/pkg/controllers/k8s/kubelet_service.go +++ b/internal/app/machined/pkg/controllers/k8s/kubelet_service.go @@ -26,6 +26,7 @@ import ( "github.com/talos-systems/talos/internal/app/machined/pkg/system" "github.com/talos-systems/talos/internal/app/machined/pkg/system/services" "github.com/talos-systems/talos/pkg/machinery/constants" + "github.com/talos-systems/talos/pkg/machinery/resources/files" "github.com/talos-systems/talos/pkg/machinery/resources/k8s" "github.com/talos-systems/talos/pkg/machinery/resources/secrets" "github.com/talos-systems/talos/pkg/machinery/resources/v1alpha1" @@ -63,7 +64,7 @@ func (ctrl *KubeletServiceController) Outputs() []controller.Output { // //nolint:gocyclo,cyclop func (ctrl *KubeletServiceController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error { - // initially, wait for the cri to be up + // initially, wait for the cri to be up and for machine-id to be generated if err := r.UpdateInputs([]controller.Input{ { Namespace: v1alpha1.NamespaceName, @@ -71,6 +72,12 @@ func (ctrl *KubeletServiceController) Run(ctx context.Context, r controller.Runt ID: pointer.ToString("cri"), Kind: controller.InputWeak, }, + { + Namespace: files.NamespaceName, + Type: files.EtcFileStatusType, + ID: pointer.ToString("machine-id"), + Kind: controller.InputWeak, + }, }); err != nil { return err } @@ -82,6 +89,15 @@ func (ctrl *KubeletServiceController) Run(ctx context.Context, r controller.Runt case <-r.EventCh(): } + _, err := r.Get(ctx, resource.NewMetadata(files.NamespaceName, files.EtcFileStatusType, "machine-id", resource.VersionUndefined)) + if err != nil { + if state.IsNotFoundError(err) { + continue + } + + return fmt.Errorf("error getting etc file status: %w", err) + } + svc, err := r.Get(ctx, resource.NewMetadata(v1alpha1.NamespaceName, v1alpha1.ServiceType, "cri", resource.VersionUndefined)) if err != nil { if state.IsNotFoundError(err) { diff --git a/internal/app/machined/pkg/system/services/kubelet.go b/internal/app/machined/pkg/system/services/kubelet.go index f9c9cfda7..d96667b2e 100644 --- a/internal/app/machined/pkg/system/services/kubelet.go +++ b/internal/app/machined/pkg/system/services/kubelet.go @@ -108,6 +108,7 @@ func (k *Kubelet) Runner(r runtime.Runtime) (runner.Runner, error) { {Type: "bind", Destination: constants.CgroupMountPath, Source: constants.CgroupMountPath, Options: []string{"rbind", "rshared", "rw"}}, {Type: "bind", Destination: "/lib/modules", Source: "/lib/modules", Options: []string{"bind", "ro"}}, {Type: "bind", Destination: "/etc/kubernetes", Source: "/etc/kubernetes", Options: []string{"bind", "rshared", "rw"}}, + {Type: "bind", Destination: "/etc/machine-id", Source: "/etc/machine-id", Options: []string{"bind", "ro"}}, {Type: "bind", Destination: "/etc/os-release", Source: "/etc/os-release", Options: []string{"bind", "ro"}}, {Type: "bind", Destination: "/etc/cni", Source: "/etc/cni", Options: []string{"rbind", "rshared", "rw"}}, {Type: "bind", Destination: "/usr/libexec/kubernetes", Source: "/usr/libexec/kubernetes", Options: []string{"rbind", "rshared", "rw"}},