diff --git a/internal/app/machined/pkg/adapters/cluster/cluster.go b/internal/app/machined/pkg/adapters/cluster/cluster.go new file mode 100644 index 000000000..b7561cd1f --- /dev/null +++ b/internal/app/machined/pkg/adapters/cluster/cluster.go @@ -0,0 +1,6 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package cluster providers adapters wrapping resources/cluster to provide additional functionality. +package cluster diff --git a/internal/app/machined/pkg/adapters/cluster/identity.go b/internal/app/machined/pkg/adapters/cluster/identity.go new file mode 100644 index 000000000..d0c8d2d17 --- /dev/null +++ b/internal/app/machined/pkg/adapters/cluster/identity.go @@ -0,0 +1,41 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package cluster + +import ( + "crypto/rand" + "io" + + "github.com/jxskiss/base62" + + "github.com/talos-systems/talos/pkg/machinery/constants" + "github.com/talos-systems/talos/pkg/resources/cluster" +) + +// IdentitySpec adapter provides identity generation. +// +//nolint:revive,golint +func IdentitySpec(r *cluster.IdentitySpec) identity { + return identity{ + IdentitySpec: r, + } +} + +type identity struct { + *cluster.IdentitySpec +} + +// Generate new identity. +func (a identity) Generate() error { + buf := make([]byte, constants.DefaultNodeIdentitySize) + + if _, err := io.ReadFull(rand.Reader, buf); err != nil { + return err + } + + a.IdentitySpec.NodeID = base62.EncodeToString(buf) + + return nil +} diff --git a/pkg/resources/cluster/identity_test.go b/internal/app/machined/pkg/adapters/cluster/identity_test.go similarity index 72% rename from pkg/resources/cluster/identity_test.go rename to internal/app/machined/pkg/adapters/cluster/identity_test.go index d5ac3020d..4e2ab4c8d 100644 --- a/pkg/resources/cluster/identity_test.go +++ b/internal/app/machined/pkg/adapters/cluster/identity_test.go @@ -10,14 +10,15 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + clusteradapter "github.com/talos-systems/talos/internal/app/machined/pkg/adapters/cluster" "github.com/talos-systems/talos/pkg/resources/cluster" ) func TestIdentityGenerate(t *testing.T) { var spec1, spec2 cluster.IdentitySpec - require.NoError(t, spec1.Generate()) - require.NoError(t, spec2.Generate()) + require.NoError(t, clusteradapter.IdentitySpec(&spec1).Generate()) + require.NoError(t, clusteradapter.IdentitySpec(&spec2).Generate()) assert.NotEqual(t, spec1, spec2) diff --git a/internal/app/machined/pkg/adapters/k8s/k8s.go b/internal/app/machined/pkg/adapters/k8s/k8s.go new file mode 100644 index 000000000..a67ed37c5 --- /dev/null +++ b/internal/app/machined/pkg/adapters/k8s/k8s.go @@ -0,0 +1,6 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package k8s providers adapters wrapping resources/k8s to provide additional functionality. +package k8s diff --git a/internal/app/machined/pkg/adapters/k8s/manifest.go b/internal/app/machined/pkg/adapters/k8s/manifest.go new file mode 100644 index 000000000..011ce01b3 --- /dev/null +++ b/internal/app/machined/pkg/adapters/k8s/manifest.go @@ -0,0 +1,87 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package k8s + +import ( + "bufio" + "bytes" + "encoding/json" + "fmt" + "io" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/util/yaml" + + "github.com/talos-systems/talos/pkg/resources/k8s" +) + +// Manifest adapter provides conversion from procfs. +// +//nolint:revive,golint +func Manifest(r *k8s.Manifest) manifest { + return manifest{ + Manifest: r, + } +} + +type manifest struct { + *k8s.Manifest +} + +// SetYAML parses manifest from YAML. +func (a manifest) SetYAML(yamlBytes []byte) error { + a.Manifest.TypedSpec().Items = nil + reader := yaml.NewYAMLReader(bufio.NewReader(bytes.NewReader(yamlBytes))) + + for { + yamlManifest, err := reader.Read() + if err != nil { + if err == io.EOF { + break + } + + return err + } + + yamlManifest = bytes.TrimSpace(yamlManifest) + + if len(yamlManifest) == 0 { + continue + } + + jsonManifest, err := yaml.ToJSON(yamlManifest) + if err != nil { + return fmt.Errorf("error converting manifest to JSON: %w", err) + } + + if bytes.Equal(jsonManifest, []byte("null")) || bytes.Equal(jsonManifest, []byte("{}")) { + // skip YAML docs which contain only comments + continue + } + + var obj unstructured.Unstructured + + if err = json.Unmarshal(jsonManifest, &obj); err != nil { + return fmt.Errorf("error loading JSON manifest into unstructured: %w", err) + } + + a.Manifest.TypedSpec().Items = append(a.Manifest.TypedSpec().Items, obj.Object) + } + + return nil +} + +// Objects returns list of unstructured object. +func (a manifest) Objects() []*unstructured.Unstructured { + result := make([]*unstructured.Unstructured, len(a.Manifest.TypedSpec().Items)) + + for i := range result { + result[i] = &unstructured.Unstructured{ + Object: a.Manifest.TypedSpec().Items[i], + } + } + + return result +} diff --git a/pkg/resources/k8s/manifest_test.go b/internal/app/machined/pkg/adapters/k8s/manifest_test.go similarity index 62% rename from pkg/resources/k8s/manifest_test.go rename to internal/app/machined/pkg/adapters/k8s/manifest_test.go index 38e2c317b..701e15653 100644 --- a/pkg/resources/k8s/manifest_test.go +++ b/internal/app/machined/pkg/adapters/k8s/manifest_test.go @@ -11,13 +11,15 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + k8sadapter "github.com/talos-systems/talos/internal/app/machined/pkg/adapters/k8s" "github.com/talos-systems/talos/pkg/resources/k8s" ) func TestManifestSetYAML(t *testing.T) { manifest := k8s.NewManifest(k8s.ControlPlaneNamespaceName, "test") + adapter := k8sadapter.Manifest(manifest) - require.NoError(t, manifest.SetYAML([]byte(strings.TrimSpace(` + require.NoError(t, adapter.SetYAML([]byte(strings.TrimSpace(` --- apiVersion: audit.k8s.io/v1beta1 kind: Policy @@ -26,14 +28,15 @@ rules: --- `)))) - assert.Len(t, manifest.Objects(), 1) - assert.Equal(t, manifest.Objects()[0].GetKind(), "Policy") + assert.Len(t, adapter.Objects(), 1) + assert.Equal(t, adapter.Objects()[0].GetKind(), "Policy") } func TestManifestSetYAMLEmptyComments(t *testing.T) { manifest := k8s.NewManifest(k8s.ControlPlaneNamespaceName, "test") + adapter := k8sadapter.Manifest(manifest) - require.NoError(t, manifest.SetYAML([]byte(strings.TrimSpace(` + require.NoError(t, adapter.SetYAML([]byte(strings.TrimSpace(` --- apiVersion: audit.k8s.io/v1beta1 kind: Policy @@ -44,6 +47,6 @@ rules: --- `)))) - assert.Len(t, manifest.Objects(), 1) - assert.Equal(t, manifest.Objects()[0].GetKind(), "Policy") + assert.Len(t, adapter.Objects(), 1) + assert.Equal(t, adapter.Objects()[0].GetKind(), "Policy") } diff --git a/internal/app/machined/pkg/adapters/k8s/static_pod.go b/internal/app/machined/pkg/adapters/k8s/static_pod.go new file mode 100644 index 000000000..93eb6abaa --- /dev/null +++ b/internal/app/machined/pkg/adapters/k8s/static_pod.go @@ -0,0 +1,52 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package k8s + +import ( + "encoding/json" + + v1 "k8s.io/api/core/v1" + + "github.com/talos-systems/talos/pkg/resources/k8s" +) + +// StaticPod adapter provides conversion from *v1.Pod. +// +//nolint:revive,golint +func StaticPod(r *k8s.StaticPod) staticPod { + return staticPod{ + StaticPod: r, + } +} + +type staticPod struct { + *k8s.StaticPod +} + +// Pod returns native Kubernetes resource. +func (a staticPod) Pod() (*v1.Pod, error) { + var spec v1.Pod + + jsonSerialized, err := json.Marshal(a.StaticPod.TypedSpec().Pod) + if err != nil { + return nil, err + } + + err = json.Unmarshal(jsonSerialized, &spec) + + return &spec, err +} + +// SetPod sets spec from native Kubernetes resource. +func (a staticPod) SetPod(podSpec *v1.Pod) error { + jsonSerialized, err := json.Marshal(podSpec) + if err != nil { + return err + } + + a.StaticPod.TypedSpec().Pod = map[string]interface{}{} + + return json.Unmarshal(jsonSerialized, &a.StaticPod.TypedSpec().Pod) +} diff --git a/internal/app/machined/pkg/adapters/k8s/static_pod_status.go b/internal/app/machined/pkg/adapters/k8s/static_pod_status.go new file mode 100644 index 000000000..991042638 --- /dev/null +++ b/internal/app/machined/pkg/adapters/k8s/static_pod_status.go @@ -0,0 +1,38 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package k8s + +import ( + "encoding/json" + + v1 "k8s.io/api/core/v1" + + "github.com/talos-systems/talos/pkg/resources/k8s" +) + +// StaticPodStatus adapter provides conversion from *v1.PodStatus. +// +//nolint:revive,golint +func StaticPodStatus(r *k8s.StaticPodStatus) staticPodStatus { + return staticPodStatus{ + StaticPodStatus: r, + } +} + +type staticPodStatus struct { + *k8s.StaticPodStatus +} + +// SetStatus sets status from native Kubernetes resource. +func (a staticPodStatus) SetStatus(status *v1.PodStatus) error { + jsonSerialized, err := json.Marshal(status) + if err != nil { + return err + } + + a.StaticPodStatus.TypedSpec().PodStatus = map[string]interface{}{} + + return json.Unmarshal(jsonSerialized, &a.StaticPodStatus.TypedSpec().PodStatus) +} diff --git a/internal/app/machined/pkg/controllers/cluster/discovery_service_test.go b/internal/app/machined/pkg/controllers/cluster/discovery_service_test.go index cb68be681..c535c2020 100644 --- a/internal/app/machined/pkg/controllers/cluster/discovery_service_test.go +++ b/internal/app/machined/pkg/controllers/cluster/discovery_service_test.go @@ -22,6 +22,7 @@ import ( "github.com/talos-systems/go-retry/retry" "inet.af/netaddr" + clusteradapter "github.com/talos-systems/talos/internal/app/machined/pkg/adapters/cluster" clusterctrl "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/cluster" "github.com/talos-systems/talos/pkg/logging" "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine" @@ -68,7 +69,7 @@ func (suite *DiscoveryServiceSuite) TestReconcile() { suite.Require().NoError(suite.state.Create(suite.ctx, discoveryConfig)) nodeIdentity := cluster.NewIdentity(cluster.NamespaceName, cluster.LocalIdentity) - suite.Require().NoError(nodeIdentity.TypedSpec().Generate()) + suite.Require().NoError(clusteradapter.IdentitySpec(nodeIdentity.TypedSpec()).Generate()) suite.Require().NoError(suite.state.Create(suite.ctx, nodeIdentity)) localAffiliate := cluster.NewAffiliate(cluster.NamespaceName, nodeIdentity.TypedSpec().NodeID) diff --git a/internal/app/machined/pkg/controllers/cluster/local_affiliate_test.go b/internal/app/machined/pkg/controllers/cluster/local_affiliate_test.go index 228382ac5..7bfa74f2c 100644 --- a/internal/app/machined/pkg/controllers/cluster/local_affiliate_test.go +++ b/internal/app/machined/pkg/controllers/cluster/local_affiliate_test.go @@ -14,6 +14,7 @@ import ( "github.com/talos-systems/go-retry/retry" "inet.af/netaddr" + clusteradapter "github.com/talos-systems/talos/internal/app/machined/pkg/adapters/cluster" clusterctrl "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/cluster" "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/talos-systems/talos/pkg/resources/cluster" @@ -38,7 +39,7 @@ func (suite *LocalAffiliateSuite) TestGeneration() { suite.Require().NoError(suite.state.Create(suite.ctx, discoveryConfig)) nodeIdentity := cluster.NewIdentity(cluster.NamespaceName, cluster.LocalIdentity) - suite.Require().NoError(nodeIdentity.TypedSpec().Generate()) + suite.Require().NoError(clusteradapter.IdentitySpec(nodeIdentity.TypedSpec()).Generate()) suite.Require().NoError(suite.state.Create(suite.ctx, nodeIdentity)) hostnameStatus := network.NewHostnameStatus(network.NamespaceName, network.HostnameID) diff --git a/internal/app/machined/pkg/controllers/cluster/node_identity.go b/internal/app/machined/pkg/controllers/cluster/node_identity.go index a4ce7d980..4a6e47062 100644 --- a/internal/app/machined/pkg/controllers/cluster/node_identity.go +++ b/internal/app/machined/pkg/controllers/cluster/node_identity.go @@ -15,6 +15,7 @@ import ( "github.com/cosi-project/runtime/pkg/state" "go.uber.org/zap" + clusteradapter "github.com/talos-systems/talos/internal/app/machined/pkg/adapters/cluster" "github.com/talos-systems/talos/internal/app/machined/pkg/controllers" "github.com/talos-systems/talos/internal/app/machined/pkg/runtime" "github.com/talos-systems/talos/pkg/machinery/constants" @@ -88,7 +89,7 @@ func (ctrl *NodeIdentityController) Run(ctx context.Context, r controller.Runtim var localIdentity cluster.IdentitySpec if err := controllers.LoadOrNewFromFile(filepath.Join(ctrl.StatePath, constants.NodeIdentityFilename), &localIdentity, func(v interface{}) error { - return v.(*cluster.IdentitySpec).Generate() + return clusteradapter.IdentitySpec(v.(*cluster.IdentitySpec)).Generate() }); err != nil { return fmt.Errorf("error caching node identity: %w", err) } diff --git a/internal/app/machined/pkg/controllers/k8s/control_plane_static_pod.go b/internal/app/machined/pkg/controllers/k8s/control_plane_static_pod.go index 744e0f661..bba30abd8 100644 --- a/internal/app/machined/pkg/controllers/k8s/control_plane_static_pod.go +++ b/internal/app/machined/pkg/controllers/k8s/control_plane_static_pod.go @@ -21,6 +21,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" + k8sadapter "github.com/talos-systems/talos/internal/app/machined/pkg/adapters/k8s" "github.com/talos-systems/talos/pkg/argsbuilder" "github.com/talos-systems/talos/pkg/machinery/constants" "github.com/talos-systems/talos/pkg/resources/config" @@ -279,8 +280,8 @@ func (ctrl *ControlPlaneStaticPodController) manageAPIServer(ctx context.Context args = append(args, builder.Args()...) - return r.Modify(ctx, k8s.NewStaticPod(k8s.ControlPlaneNamespaceName, "kube-apiserver", nil), func(r resource.Resource) error { - r.(*k8s.StaticPod).SetPod(&v1.Pod{ + return r.Modify(ctx, k8s.NewStaticPod(k8s.ControlPlaneNamespaceName, "kube-apiserver"), func(r resource.Resource) error { + return k8sadapter.StaticPod(r.(*k8s.StaticPod)).SetPod(&v1.Pod{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1", Kind: "Pod", @@ -346,8 +347,6 @@ func (ctrl *ControlPlaneStaticPodController) manageAPIServer(ctx context.Context }, volumes(cfg.ExtraVolumes)...), }, }) - - return nil }) } @@ -402,8 +401,8 @@ func (ctrl *ControlPlaneStaticPodController) manageControllerManager(ctx context args = append(args, builder.Args()...) //nolint:dupl - return r.Modify(ctx, k8s.NewStaticPod(k8s.ControlPlaneNamespaceName, "kube-controller-manager", nil), func(r resource.Resource) error { - r.(*k8s.StaticPod).SetPod(&v1.Pod{ + return r.Modify(ctx, k8s.NewStaticPod(k8s.ControlPlaneNamespaceName, "kube-controller-manager"), func(r resource.Resource) error { + return k8sadapter.StaticPod(r.(*k8s.StaticPod)).SetPod(&v1.Pod{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1", Kind: "Pod", @@ -471,8 +470,6 @@ func (ctrl *ControlPlaneStaticPodController) manageControllerManager(ctx context }, volumes(cfg.ExtraVolumes)...), }, }) - - return nil }) } @@ -508,8 +505,8 @@ func (ctrl *ControlPlaneStaticPodController) manageScheduler(ctx context.Context args = append(args, builder.Args()...) //nolint:dupl - return r.Modify(ctx, k8s.NewStaticPod(k8s.ControlPlaneNamespaceName, "kube-scheduler", nil), func(r resource.Resource) error { - r.(*k8s.StaticPod).SetPod(&v1.Pod{ + return r.Modify(ctx, k8s.NewStaticPod(k8s.ControlPlaneNamespaceName, "kube-scheduler"), func(r resource.Resource) error { + return k8sadapter.StaticPod(r.(*k8s.StaticPod)).SetPod(&v1.Pod{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1", Kind: "Pod", @@ -577,7 +574,5 @@ func (ctrl *ControlPlaneStaticPodController) manageScheduler(ctx context.Context }, volumes(cfg.ExtraVolumes)...), }, }) - - return nil }) } diff --git a/internal/app/machined/pkg/controllers/k8s/control_plane_static_pod_test.go b/internal/app/machined/pkg/controllers/k8s/control_plane_static_pod_test.go index 7d5a4b8ff..2648cfe50 100644 --- a/internal/app/machined/pkg/controllers/k8s/control_plane_static_pod_test.go +++ b/internal/app/machined/pkg/controllers/k8s/control_plane_static_pod_test.go @@ -24,6 +24,7 @@ import ( "github.com/talos-systems/go-retry/retry" v1 "k8s.io/api/core/v1" + k8sadapter "github.com/talos-systems/talos/internal/app/machined/pkg/adapters/k8s" k8sctrl "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/k8s" "github.com/talos-systems/talos/pkg/logging" "github.com/talos-systems/talos/pkg/machinery/constants" @@ -174,7 +175,8 @@ func (suite *ControlPlaneStaticPodSuite) TestReconcileExtraMounts() { r, err := suite.state.Get(suite.ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.StaticPodType, "kube-apiserver", resource.VersionUndefined)) suite.Require().NoError(err) - apiServerPod := r.(*k8s.StaticPod).Pod() + apiServerPod, err := k8sadapter.StaticPod(r.(*k8s.StaticPod)).Pod() + suite.Require().NoError(err) suite.Assert().Len(apiServerPod.Spec.Volumes, 2) suite.Assert().Len(apiServerPod.Spec.Containers[0].VolumeMounts, 2) @@ -271,7 +273,8 @@ func (suite *ControlPlaneStaticPodSuite) TestReconcileExtraArgs() { r, err := suite.state.Get(suite.ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.StaticPodType, "kube-apiserver", resource.VersionUndefined)) suite.Require().NoError(err) - apiServerPod := r.(*k8s.StaticPod).Pod() + apiServerPod, err := k8sadapter.StaticPod(r.(*k8s.StaticPod)).Pod() + suite.Require().NoError(err) suite.Require().NotEmpty(apiServerPod.Spec.Containers) diff --git a/internal/app/machined/pkg/controllers/k8s/extra_manifest.go b/internal/app/machined/pkg/controllers/k8s/extra_manifest.go index e11cf3184..35d8181d3 100644 --- a/internal/app/machined/pkg/controllers/k8s/extra_manifest.go +++ b/internal/app/machined/pkg/controllers/k8s/extra_manifest.go @@ -20,6 +20,7 @@ import ( "github.com/hashicorp/go-multierror" "go.uber.org/zap" + k8sadapter "github.com/talos-systems/talos/internal/app/machined/pkg/adapters/k8s" "github.com/talos-systems/talos/pkg/resources/config" "github.com/talos-systems/talos/pkg/resources/k8s" "github.com/talos-systems/talos/pkg/resources/network" @@ -208,7 +209,7 @@ func (ctrl *ExtraManifestController) processURL(ctx context.Context, r controlle if err = r.Modify(ctx, k8s.NewManifest(k8s.ControlPlaneNamespaceName, id), func(r resource.Resource) error { - return r.(*k8s.Manifest).SetYAML(contents) + return k8sadapter.Manifest(r.(*k8s.Manifest)).SetYAML(contents) }); err != nil { err = fmt.Errorf("error updating manifests: %w", err) @@ -223,7 +224,7 @@ func (ctrl *ExtraManifestController) processInline(ctx context.Context, r contro ctx, k8s.NewManifest(k8s.ControlPlaneNamespaceName, id), func(r resource.Resource) error { - return r.(*k8s.Manifest).SetYAML([]byte(manifest.InlineManifest)) + return k8sadapter.Manifest(r.(*k8s.Manifest)).SetYAML([]byte(manifest.InlineManifest)) }, ) if err != nil { diff --git a/internal/app/machined/pkg/controllers/k8s/extra_manifest_test.go b/internal/app/machined/pkg/controllers/k8s/extra_manifest_test.go index 1fd58ee59..8a5464e85 100644 --- a/internal/app/machined/pkg/controllers/k8s/extra_manifest_test.go +++ b/internal/app/machined/pkg/controllers/k8s/extra_manifest_test.go @@ -23,6 +23,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/talos-systems/go-retry/retry" + k8sadapter "github.com/talos-systems/talos/internal/app/machined/pkg/adapters/k8s" k8sctrl "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/k8s" "github.com/talos-systems/talos/pkg/logging" "github.com/talos-systems/talos/pkg/resources/config" @@ -132,9 +133,9 @@ metadata: manifest := r.(*k8s.Manifest) //nolint:errcheck,forcetypeassert - suite.Assert().Len(manifest.Objects(), 2) - suite.Assert().Equal("ci", manifest.Objects()[0].GetName()) - suite.Assert().Equal("build", manifest.Objects()[1].GetName()) + suite.Assert().Len(k8sadapter.Manifest(manifest).Objects(), 2) + suite.Assert().Equal("ci", k8sadapter.Manifest(manifest).Objects()[0].GetName()) + suite.Assert().Equal("build", k8sadapter.Manifest(manifest).Objects()[1].GetName()) } func (suite *ExtraManifestSuite) TearDownTest() { diff --git a/internal/app/machined/pkg/controllers/k8s/kubelet_static_pod_controller.go b/internal/app/machined/pkg/controllers/k8s/kubelet_static_pod_controller.go index 0635b8bc1..a6782e9ed 100644 --- a/internal/app/machined/pkg/controllers/k8s/kubelet_static_pod_controller.go +++ b/internal/app/machined/pkg/controllers/k8s/kubelet_static_pod_controller.go @@ -21,6 +21,7 @@ import ( "go.uber.org/zap" yaml "gopkg.in/yaml.v3" + k8sadapter "github.com/talos-systems/talos/internal/app/machined/pkg/adapters/k8s" "github.com/talos-systems/talos/pkg/kubernetes/kubelet" "github.com/talos-systems/talos/pkg/machinery/constants" "github.com/talos-systems/talos/pkg/resources/k8s" @@ -329,9 +330,7 @@ func (ctrl *KubeletStaticPodController) refreshPodStatus(ctx context.Context, r podsSeen[statusID] = struct{}{} if err = r.Modify(ctx, k8s.NewStaticPodStatus(k8s.ControlPlaneNamespaceName, statusID), func(r resource.Resource) error { - r.(*k8s.StaticPodStatus).SetStatus(&pod.Status) - - return nil + return k8sadapter.StaticPodStatus(r.(*k8s.StaticPodStatus)).SetStatus(&pod.Status) }); err != nil { return fmt.Errorf("error updating pod status: %w", err) } diff --git a/internal/app/machined/pkg/controllers/k8s/manifest.go b/internal/app/machined/pkg/controllers/k8s/manifest.go index 2e0f47358..15b5b36a5 100644 --- a/internal/app/machined/pkg/controllers/k8s/manifest.go +++ b/internal/app/machined/pkg/controllers/k8s/manifest.go @@ -18,6 +18,7 @@ import ( "github.com/cosi-project/runtime/pkg/state" "go.uber.org/zap" + k8sadapter "github.com/talos-systems/talos/internal/app/machined/pkg/adapters/k8s" "github.com/talos-systems/talos/pkg/resources/config" "github.com/talos-systems/talos/pkg/resources/k8s" "github.com/talos-systems/talos/pkg/resources/secrets" @@ -110,7 +111,7 @@ func (ctrl *ManifestController) Run(ctx context.Context, r controller.Runtime, l if err = r.Modify(ctx, k8s.NewManifest(k8s.ControlPlaneNamespaceName, renderedManifest.name), func(r resource.Resource) error { - return r.(*k8s.Manifest).SetYAML(renderedManifest.data) + return k8sadapter.Manifest(r.(*k8s.Manifest)).SetYAML(renderedManifest.data) }); err != nil { return fmt.Errorf("error updating manifests: %w", err) } diff --git a/internal/app/machined/pkg/controllers/k8s/manifest_apply.go b/internal/app/machined/pkg/controllers/k8s/manifest_apply.go index 081f4cab1..e0678814f 100644 --- a/internal/app/machined/pkg/controllers/k8s/manifest_apply.go +++ b/internal/app/machined/pkg/controllers/k8s/manifest_apply.go @@ -29,6 +29,7 @@ import ( "k8s.io/client-go/tools/clientcmd" clientcmdapi "k8s.io/client-go/tools/clientcmd/api" + k8sadapter "github.com/talos-systems/talos/internal/app/machined/pkg/adapters/k8s" "github.com/talos-systems/talos/internal/pkg/etcd" "github.com/talos-systems/talos/pkg/logging" "github.com/talos-systems/talos/pkg/machinery/constants" @@ -212,7 +213,7 @@ func (ctrl *ManifestApplyController) apply(ctx context.Context, logger *zap.Logg objects := make([]*unstructured.Unstructured, 0, len(manifests.Items)) for _, manifest := range manifests.Items { - objects = append(objects, manifest.(*k8s.Manifest).Objects()...) + objects = append(objects, k8sadapter.Manifest(manifest.(*k8s.Manifest)).Objects()...) } // sort the list so that namespaces come first, followed by CRDs and everything else after that diff --git a/internal/app/machined/pkg/controllers/k8s/manifest_test.go b/internal/app/machined/pkg/controllers/k8s/manifest_test.go index cfe560579..b79cf0503 100644 --- a/internal/app/machined/pkg/controllers/k8s/manifest_test.go +++ b/internal/app/machined/pkg/controllers/k8s/manifest_test.go @@ -22,6 +22,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/talos-systems/go-retry/retry" + k8sadapter "github.com/talos-systems/talos/internal/app/machined/pkg/adapters/k8s" k8sctrl "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/k8s" "github.com/talos-systems/talos/pkg/logging" "github.com/talos-systems/talos/pkg/machinery/constants" @@ -208,11 +209,11 @@ func (suite *ManifestSuite) TestReconcileKubeProxyExtraArgs() { suite.Require().NoError(err) manifest := r.(*k8s.Manifest) //nolint:errcheck,forcetypeassert - suite.Assert().Len(manifest.Objects(), 3) + suite.Assert().Len(k8sadapter.Manifest(manifest).Objects(), 3) - suite.Assert().Equal("DaemonSet", manifest.Objects()[0].GetKind()) + suite.Assert().Equal("DaemonSet", k8sadapter.Manifest(manifest).Objects()[0].GetKind()) - ds := manifest.Objects()[0].Object + ds := k8sadapter.Manifest(manifest).Objects()[0].Object containerSpec := ds["spec"].(map[string]interface{})["template"].(map[string]interface{})["spec"].(map[string]interface{})["containers"].([]interface{})[0] args := containerSpec.(map[string]interface{})["command"].([]interface{}) //nolint:errcheck,forcetypeassert diff --git a/internal/app/machined/pkg/controllers/kubespan/peer_spec_test.go b/internal/app/machined/pkg/controllers/kubespan/peer_spec_test.go index 3cb96df2d..d53f956a7 100644 --- a/internal/app/machined/pkg/controllers/kubespan/peer_spec_test.go +++ b/internal/app/machined/pkg/controllers/kubespan/peer_spec_test.go @@ -13,6 +13,7 @@ import ( "github.com/talos-systems/go-retry/retry" "inet.af/netaddr" + clusteradapter "github.com/talos-systems/talos/internal/app/machined/pkg/adapters/cluster" kubespanctrl "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/kubespan" "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/talos-systems/talos/pkg/machinery/constants" @@ -46,7 +47,7 @@ func (suite *PeerSpecSuite) TestReconcile() { suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) nodeIdentity := cluster.NewIdentity(cluster.NamespaceName, cluster.LocalIdentity) - suite.Require().NoError(nodeIdentity.TypedSpec().Generate()) + suite.Require().NoError(clusteradapter.IdentitySpec(nodeIdentity.TypedSpec()).Generate()) suite.Require().NoError(suite.state.Create(suite.ctx, nodeIdentity)) affiliate1 := cluster.NewAffiliate(cluster.NamespaceName, "7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC") @@ -183,7 +184,7 @@ func (suite *PeerSpecSuite) TestIPOverlap() { suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) nodeIdentity := cluster.NewIdentity(cluster.NamespaceName, cluster.LocalIdentity) - suite.Require().NoError(nodeIdentity.TypedSpec().Generate()) + suite.Require().NoError(clusteradapter.IdentitySpec(nodeIdentity.TypedSpec()).Generate()) suite.Require().NoError(suite.state.Create(suite.ctx, nodeIdentity)) affiliate1 := cluster.NewAffiliate(cluster.NamespaceName, "7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC") diff --git a/pkg/resources/.importvet.yaml b/pkg/resources/.importvet.yaml index cba40f71d..f7369bd01 100644 --- a/pkg/resources/.importvet.yaml +++ b/pkg/resources/.importvet.yaml @@ -9,10 +9,10 @@ rules: action: allow - regexp: ^github.com/talos-systems/talos/pkg/machinery action: allow - #- regexp: ^k8s.io/ - # action: deny - #- regexp: ^github.com/jxskiss/base62 - # action: deny + - regexp: ^k8s.io/ + action: deny + - regexp: ^github.com/jxskiss/base62 + action: deny #- regexp: ^github.com/mdlayher/netlink # action: deny #- regexp: ^github.com/mdlayher/netx diff --git a/pkg/resources/cluster/identity.go b/pkg/resources/cluster/identity.go index e6cfc6449..52ee4a531 100644 --- a/pkg/resources/cluster/identity.go +++ b/pkg/resources/cluster/identity.go @@ -5,15 +5,10 @@ package cluster import ( - "crypto/rand" "fmt" - "io" "github.com/cosi-project/runtime/pkg/resource" "github.com/cosi-project/runtime/pkg/resource/meta" - "github.com/jxskiss/base62" - - "github.com/talos-systems/talos/pkg/machinery/constants" ) // IdentityType is type of Identity resource. @@ -91,16 +86,3 @@ func (r *Identity) ResourceDefinition() meta.ResourceDefinitionSpec { func (r *Identity) TypedSpec() *IdentitySpec { return &r.spec } - -// Generate new identity. -func (spec *IdentitySpec) Generate() error { - buf := make([]byte, constants.DefaultNodeIdentitySize) - - if _, err := io.ReadFull(rand.Reader, buf); err != nil { - return err - } - - spec.NodeID = base62.EncodeToString(buf) - - return nil -} diff --git a/pkg/resources/k8s/manifest.go b/pkg/resources/k8s/manifest.go index 492009c69..61def1d1a 100644 --- a/pkg/resources/k8s/manifest.go +++ b/pkg/resources/k8s/manifest.go @@ -5,16 +5,10 @@ package k8s import ( - "bufio" - "bytes" - "encoding/json" "fmt" - "io" "github.com/cosi-project/runtime/pkg/resource" "github.com/cosi-project/runtime/pkg/resource/meta" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/util/yaml" ) // ManifestType is type of Manifest resource. @@ -23,28 +17,24 @@ const ManifestType = resource.Type("Manifests.kubernetes.talos.dev") // Manifest resource holds definition of kubelet static pod. type Manifest struct { md resource.Metadata - spec *manifestSpec + spec *ManifestSpec } -type manifestSpec struct { - Items []*unstructured.Unstructured +// ManifestSpec holds the Kubernetes resources spec. +type ManifestSpec struct { + Items []map[string]interface{} } -func (spec *manifestSpec) MarshalYAML() (interface{}, error) { - result := make([]map[string]interface{}, 0, len(spec.Items)) - - for _, obj := range spec.Items { - result = append(result, obj.Object) - } - - return result, nil +// MarshalYAML implements yaml.Marshaler. +func (spec *ManifestSpec) MarshalYAML() (interface{}, error) { + return spec.Items, nil } // NewManifest initializes an empty Manifest resource. func NewManifest(namespace resource.Namespace, id resource.ID) *Manifest { r := &Manifest{ md: resource.NewMetadata(namespace, ManifestType, id, resource.VersionUndefined), - spec: &manifestSpec{}, + spec: &ManifestSpec{}, } r.md.BumpVersion() @@ -68,17 +58,11 @@ func (r *Manifest) String() string { // DeepCopy implements resource.Resource. func (r *Manifest) DeepCopy() resource.Resource { - spec := &manifestSpec{ - Items: make([]*unstructured.Unstructured, len(r.spec.Items)), - } - - for i := range r.spec.Items { - spec.Items[i] = r.spec.Items[i].DeepCopy() - } - return &Manifest{ - md: r.md, - spec: spec, + md: r.md, + spec: &ManifestSpec{ + Items: append([]map[string]interface{}(nil), r.spec.Items...), + }, } } @@ -91,50 +75,7 @@ func (r *Manifest) ResourceDefinition() meta.ResourceDefinitionSpec { } } -// SetYAML parses manifest from YAML. -func (r *Manifest) SetYAML(yamlBytes []byte) error { - r.spec.Items = nil - reader := yaml.NewYAMLReader(bufio.NewReader(bytes.NewReader(yamlBytes))) - - for { - yamlManifest, err := reader.Read() - if err != nil { - if err == io.EOF { - break - } - - return err - } - - yamlManifest = bytes.TrimSpace(yamlManifest) - - if len(yamlManifest) == 0 { - continue - } - - jsonManifest, err := yaml.ToJSON(yamlManifest) - if err != nil { - return fmt.Errorf("error converting manifest to JSON: %w", err) - } - - if bytes.Equal(jsonManifest, []byte("null")) || bytes.Equal(jsonManifest, []byte("{}")) { - // skip YAML docs which contain only comments - continue - } - - obj := new(unstructured.Unstructured) - - if err = json.Unmarshal(jsonManifest, obj); err != nil { - return fmt.Errorf("error loading JSON manifest into unstructured: %w", err) - } - - r.spec.Items = append(r.spec.Items, obj) - } - - return nil -} - -// Objects returns list of unstrustured object. -func (r *Manifest) Objects() []*unstructured.Unstructured { - return r.spec.Items +// TypedSpec returns .spec. +func (r *Manifest) TypedSpec() *ManifestSpec { + return r.spec } diff --git a/pkg/resources/k8s/static_pod.go b/pkg/resources/k8s/static_pod.go index 1fb60734f..32944f2e0 100644 --- a/pkg/resources/k8s/static_pod.go +++ b/pkg/resources/k8s/static_pod.go @@ -5,12 +5,10 @@ package k8s import ( - "encoding/json" "fmt" "github.com/cosi-project/runtime/pkg/resource" "github.com/cosi-project/runtime/pkg/resource/meta" - v1 "k8s.io/api/core/v1" ) // StaticPodType is type of StaticPod resource. @@ -19,33 +17,24 @@ const StaticPodType = resource.Type("StaticPods.kubernetes.talos.dev") // StaticPod resource holds definition of kubelet static pod. type StaticPod struct { md resource.Metadata - spec *staticPodSpec + spec *StaticPodSpec } -type staticPodSpec struct { - *v1.Pod +// StaticPodSpec describes static pod spec, it contains marshaled *v1.Pod spec. +type StaticPodSpec struct { + Pod map[string]interface{} } -func (spec *staticPodSpec) MarshalYAML() (interface{}, error) { - jsonSerialized, err := json.Marshal(spec.Pod) - if err != nil { - return nil, err - } - - var obj interface{} - - err = json.Unmarshal(jsonSerialized, &obj) - - return obj, err +// MarshalYAML implements yaml.Marshaler. +func (spec *StaticPodSpec) MarshalYAML() (interface{}, error) { + return spec.Pod, nil } // NewStaticPod initializes a StaticPod resource. -func NewStaticPod(namespace resource.Namespace, id resource.ID, spec *v1.Pod) *StaticPod { +func NewStaticPod(namespace resource.Namespace, id resource.ID) *StaticPod { r := &StaticPod{ - md: resource.NewMetadata(namespace, StaticPodType, id, resource.VersionUndefined), - spec: &staticPodSpec{ - Pod: spec, - }, + md: resource.NewMetadata(namespace, StaticPodType, id, resource.VersionUndefined), + spec: &StaticPodSpec{}, } r.md.BumpVersion() @@ -71,8 +60,8 @@ func (r *StaticPod) String() string { func (r *StaticPod) DeepCopy() resource.Resource { return &StaticPod{ md: r.md, - spec: &staticPodSpec{ - Pod: r.spec.Pod.DeepCopy(), + spec: &StaticPodSpec{ + Pod: r.spec.Pod, }, } } @@ -86,12 +75,7 @@ func (r *StaticPod) ResourceDefinition() meta.ResourceDefinitionSpec { } } -// Pod returns pod definition. -func (r *StaticPod) Pod() *v1.Pod { - return r.spec.Pod -} - -// SetPod sets pod definition. -func (r *StaticPod) SetPod(podSpec *v1.Pod) { - r.spec.Pod = podSpec +// TypedSpec returns .spec. +func (r *StaticPod) TypedSpec() *StaticPodSpec { + return r.spec } diff --git a/pkg/resources/k8s/static_pod_status.go b/pkg/resources/k8s/static_pod_status.go index 08f81451c..cccb5dc1d 100644 --- a/pkg/resources/k8s/static_pod_status.go +++ b/pkg/resources/k8s/static_pod_status.go @@ -5,12 +5,10 @@ package k8s import ( - "encoding/json" "fmt" "github.com/cosi-project/runtime/pkg/resource" "github.com/cosi-project/runtime/pkg/resource/meta" - v1 "k8s.io/api/core/v1" ) // StaticPodStatusType is type of StaticPodStatus resource. @@ -19,32 +17,24 @@ const StaticPodStatusType = resource.Type("StaticPodStatuses.kubernetes.talos.de // StaticPodStatus resource holds definition of kubelet static pod. type StaticPodStatus struct { md resource.Metadata - spec *staticPodStatusSpec + spec *StaticPodStatusSpec } -// staticPodStatusSpec describes kubelet static pod status. -type staticPodStatusSpec struct { - *v1.PodStatus +// StaticPodStatusSpec describes kubelet static pod status. +type StaticPodStatusSpec struct { + PodStatus map[string]interface{} } -func (spec *staticPodStatusSpec) MarshalYAML() (interface{}, error) { - jsonSerialized, err := json.Marshal(spec.PodStatus) - if err != nil { - return nil, err - } - - var obj interface{} - - err = json.Unmarshal(jsonSerialized, &obj) - - return obj, err +// MarshalYAML implements yaml.Marshaler. +func (spec *StaticPodStatusSpec) MarshalYAML() (interface{}, error) { + return spec.PodStatus, nil } // NewStaticPodStatus initializes a StaticPodStatus resource. func NewStaticPodStatus(namespace resource.Namespace, id resource.ID) *StaticPodStatus { r := &StaticPodStatus{ md: resource.NewMetadata(namespace, StaticPodStatusType, id, resource.VersionUndefined), - spec: &staticPodStatusSpec{}, + spec: &StaticPodStatusSpec{}, } r.md.BumpVersion() @@ -70,8 +60,8 @@ func (r *StaticPodStatus) String() string { func (r *StaticPodStatus) DeepCopy() resource.Resource { return &StaticPodStatus{ md: r.md, - spec: &staticPodStatusSpec{ - PodStatus: r.spec.PodStatus.DeepCopy(), + spec: &StaticPodStatusSpec{ + PodStatus: r.spec.PodStatus, }, } } @@ -91,12 +81,7 @@ func (r *StaticPodStatus) ResourceDefinition() meta.ResourceDefinitionSpec { } } -// Status gets pod status. -func (r *StaticPodStatus) Status() *v1.PodStatus { - return r.spec.PodStatus -} - -// SetStatus sets pod status. -func (r *StaticPodStatus) SetStatus(status *v1.PodStatus) { - r.spec.PodStatus = status +// TypedSpec returns .spec. +func (r *StaticPodStatus) TypedSpec() *StaticPodStatusSpec { + return r.spec }