mirror of
https://github.com/siderolabs/talos.git
synced 2026-05-04 20:06:18 +02:00
fix: write etcd PKI files in a controller
Instead of writing PKI "once" around the startup time, keep writing PKI files as the certificates get updated. `etcd` is able to reload certificates, so we should keep updating them e.g. if the hostname/IPs change over time. Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
This commit is contained in:
parent
bb4abc0961
commit
a2aea97263
@ -253,8 +253,7 @@ COPY --from=generate-build /api/storage/*.pb.go /pkg/machinery/api/storage/
|
||||
COPY --from=generate-build /api/resource/*.pb.go /pkg/machinery/api/resource/
|
||||
COPY --from=generate-build /api/resource/secrets/*.pb.go /pkg/machinery/api/resource/secrets/
|
||||
COPY --from=generate-build /api/inspect/*.pb.go /pkg/machinery/api/inspect/
|
||||
COPY --from=go-generate /src/pkg/machinery/resources/kubespan/ /pkg/machinery/resources/kubespan/
|
||||
COPY --from=go-generate /src/pkg/machinery/resources/network/ /pkg/machinery/resources/network/
|
||||
COPY --from=go-generate /src/pkg/machinery/resources/ /pkg/machinery/resources/
|
||||
COPY --from=go-generate /src/pkg/machinery/config/types/v1alpha1/ /pkg/machinery/config/types/v1alpha1/
|
||||
COPY --from=go-generate /src/pkg/machinery/nethelpers/ /pkg/machinery/nethelpers/
|
||||
COPY --from=go-generate /src/pkg/machinery/extensions/ /pkg/machinery/extensions/
|
||||
|
||||
6
internal/app/machined/pkg/controllers/etcd/etcd.go
Normal file
6
internal/app/machined/pkg/controllers/etcd/etcd.go
Normal file
@ -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 etcd provides controllers which manage etcd resources.
|
||||
package etcd
|
||||
148
internal/app/machined/pkg/controllers/etcd/pki.go
Normal file
148
internal/app/machined/pkg/controllers/etcd/pki.go
Normal file
@ -0,0 +1,148 @@
|
||||
// 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 etcd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/controller"
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"github.com/cosi-project/runtime/pkg/safe"
|
||||
"github.com/cosi-project/runtime/pkg/state"
|
||||
"github.com/siderolabs/go-pointer"
|
||||
"github.com/talos-systems/crypto/x509"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/talos-systems/talos/pkg/filetree"
|
||||
"github.com/talos-systems/talos/pkg/machinery/constants"
|
||||
"github.com/talos-systems/talos/pkg/machinery/resources/etcd"
|
||||
"github.com/talos-systems/talos/pkg/machinery/resources/secrets"
|
||||
)
|
||||
|
||||
// PKIController renders manifests based on templates and config/secrets.
|
||||
type PKIController struct{}
|
||||
|
||||
// Name implements controller.Controller interface.
|
||||
func (ctrl *PKIController) Name() string {
|
||||
return "etcd.PKIController"
|
||||
}
|
||||
|
||||
// Inputs implements controller.Controller interface.
|
||||
func (ctrl *PKIController) Inputs() []controller.Input {
|
||||
return []controller.Input{
|
||||
{
|
||||
Namespace: secrets.NamespaceName,
|
||||
Type: secrets.EtcdRootType,
|
||||
ID: pointer.To(secrets.EtcdRootID),
|
||||
Kind: controller.InputWeak,
|
||||
},
|
||||
{
|
||||
Namespace: secrets.NamespaceName,
|
||||
Type: secrets.EtcdType,
|
||||
ID: pointer.To(secrets.EtcdID),
|
||||
Kind: controller.InputWeak,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Outputs implements controller.Controller interface.
|
||||
func (ctrl *PKIController) Outputs() []controller.Output {
|
||||
return []controller.Output{
|
||||
{
|
||||
Type: etcd.PKIStatusType,
|
||||
Kind: controller.OutputExclusive,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Run implements controller.Controller interface.
|
||||
//
|
||||
//nolint:gocyclo
|
||||
func (ctrl *PKIController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case <-r.EventCh():
|
||||
}
|
||||
|
||||
rootScrts, err := safe.ReaderGet[*secrets.EtcdRoot](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.EtcdRootType, secrets.EtcdRootID, resource.VersionUndefined))
|
||||
if err != nil {
|
||||
if state.IsNotFoundError(err) {
|
||||
continue
|
||||
}
|
||||
|
||||
return fmt.Errorf("error getting root secrets: %w", err)
|
||||
}
|
||||
|
||||
scrts, err := safe.ReaderGet[*secrets.Etcd](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.EtcdType, secrets.EtcdID, resource.VersionUndefined))
|
||||
if err != nil {
|
||||
if state.IsNotFoundError(err) {
|
||||
continue
|
||||
}
|
||||
|
||||
return fmt.Errorf("error getting secrets: %w", err)
|
||||
}
|
||||
|
||||
if err = os.MkdirAll(constants.EtcdPKIPath, 0o700); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = os.WriteFile(constants.KubernetesEtcdCACert, rootScrts.TypedSpec().EtcdCA.Crt, 0o400); err != nil {
|
||||
return fmt.Errorf("failed to write CA certificate: %w", err)
|
||||
}
|
||||
|
||||
if err = os.WriteFile(constants.KubernetesEtcdCAKey, rootScrts.TypedSpec().EtcdCA.Key, 0o400); err != nil {
|
||||
return fmt.Errorf("failed to write CA key: %w", err)
|
||||
}
|
||||
|
||||
etcdCerts := scrts.TypedSpec()
|
||||
|
||||
for _, keypair := range []struct {
|
||||
getter func() *x509.PEMEncodedCertificateAndKey
|
||||
keyPath string
|
||||
certPath string
|
||||
}{
|
||||
{
|
||||
getter: func() *x509.PEMEncodedCertificateAndKey { return etcdCerts.Etcd },
|
||||
keyPath: constants.KubernetesEtcdKey,
|
||||
certPath: constants.KubernetesEtcdCert,
|
||||
},
|
||||
{
|
||||
getter: func() *x509.PEMEncodedCertificateAndKey { return etcdCerts.EtcdPeer },
|
||||
keyPath: constants.KubernetesEtcdPeerKey,
|
||||
certPath: constants.KubernetesEtcdPeerCert,
|
||||
},
|
||||
{
|
||||
getter: func() *x509.PEMEncodedCertificateAndKey { return etcdCerts.EtcdAdmin },
|
||||
keyPath: constants.KubernetesEtcdAdminKey,
|
||||
certPath: constants.KubernetesEtcdAdminCert,
|
||||
},
|
||||
} {
|
||||
if err = os.WriteFile(keypair.keyPath, keypair.getter().Key, 0o400); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = os.WriteFile(keypair.certPath, keypair.getter().Crt, 0o400); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = filetree.ChownRecursive(constants.EtcdPKIPath, constants.EtcdUserID, constants.EtcdUserID); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err = safe.WriterModify(ctx, r, etcd.NewPKIStatus(etcd.NamespaceName, etcd.PKIID), func(status *etcd.PKIStatus) error {
|
||||
status.TypedSpec().Ready = true
|
||||
status.TypedSpec().Version = scrts.Metadata().Version().String()
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return fmt.Errorf("error updating PKI status: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -21,6 +21,7 @@ import (
|
||||
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/controllers/cluster"
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/controllers/config"
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/controllers/etcd"
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/controllers/files"
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/controllers/hardware"
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/controllers/k8s"
|
||||
@ -103,6 +104,7 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error
|
||||
&config.MachineTypeController{},
|
||||
&config.K8sAddressFilterController{},
|
||||
&config.K8sControlPlaneController{},
|
||||
&etcd.PKIController{},
|
||||
&files.CRIConfigPartsController{},
|
||||
&files.CRIRegistryConfigController{},
|
||||
&files.EtcFileController{
|
||||
|
||||
@ -16,6 +16,7 @@ import (
|
||||
talosconfig "github.com/talos-systems/talos/pkg/machinery/config"
|
||||
"github.com/talos-systems/talos/pkg/machinery/resources/cluster"
|
||||
"github.com/talos-systems/talos/pkg/machinery/resources/config"
|
||||
"github.com/talos-systems/talos/pkg/machinery/resources/etcd"
|
||||
"github.com/talos-systems/talos/pkg/machinery/resources/files"
|
||||
"github.com/talos-systems/talos/pkg/machinery/resources/hardware"
|
||||
"github.com/talos-systems/talos/pkg/machinery/resources/k8s"
|
||||
@ -63,6 +64,7 @@ func NewState() (*State, error) {
|
||||
{cluster.NamespaceName, "Cluster configuration and discovery resources."},
|
||||
{cluster.RawNamespaceName, "Cluster unmerged raw resources."},
|
||||
{config.NamespaceName, "Talos node configuration."},
|
||||
{etcd.NamespaceName, "etcd resources."},
|
||||
{files.NamespaceName, "Files and file-like resources."},
|
||||
{hardware.NamespaceName, "Hardware resources."},
|
||||
{k8s.NamespaceName, "Kubernetes all node types resources."},
|
||||
@ -87,6 +89,7 @@ func NewState() (*State, error) {
|
||||
&cluster.Member{},
|
||||
&config.MachineConfig{},
|
||||
&config.MachineType{},
|
||||
&etcd.PKIStatus{},
|
||||
&files.EtcFileSpec{},
|
||||
&files.EtcFileStatus{},
|
||||
&hardware.Processor{},
|
||||
|
||||
@ -9,7 +9,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
goruntime "runtime"
|
||||
@ -23,7 +22,6 @@ import (
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"github.com/cosi-project/runtime/pkg/state"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/talos-systems/crypto/x509"
|
||||
"github.com/talos-systems/go-retry/retry"
|
||||
"github.com/talos-systems/net"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
@ -42,13 +40,14 @@ import (
|
||||
"github.com/talos-systems/talos/internal/pkg/etcd"
|
||||
"github.com/talos-systems/talos/pkg/argsbuilder"
|
||||
"github.com/talos-systems/talos/pkg/conditions"
|
||||
"github.com/talos-systems/talos/pkg/filetree"
|
||||
"github.com/talos-systems/talos/pkg/logging"
|
||||
machineapi "github.com/talos-systems/talos/pkg/machinery/api/machine"
|
||||
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine"
|
||||
"github.com/talos-systems/talos/pkg/machinery/constants"
|
||||
etcdresource "github.com/talos-systems/talos/pkg/machinery/resources/etcd"
|
||||
"github.com/talos-systems/talos/pkg/machinery/resources/k8s"
|
||||
"github.com/talos-systems/talos/pkg/machinery/resources/network"
|
||||
"github.com/talos-systems/talos/pkg/machinery/resources/secrets"
|
||||
timeresource "github.com/talos-systems/talos/pkg/machinery/resources/time"
|
||||
)
|
||||
|
||||
@ -87,7 +86,7 @@ func (e *Etcd) PreFunc(ctx context.Context, r runtime.Runtime) (err error) {
|
||||
}
|
||||
|
||||
// Make sure etcd user can access files in the data directory.
|
||||
if err = chownRecursive(constants.EtcdDataPath, constants.EtcdUserID, constants.EtcdUserID); err != nil {
|
||||
if err = filetree.ChownRecursive(constants.EtcdDataPath, constants.EtcdUserID, constants.EtcdUserID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -126,7 +125,7 @@ func (e *Etcd) PreFunc(ctx context.Context, r runtime.Runtime) (err error) {
|
||||
panic(fmt.Sprintf("unexpected machine type %v", t))
|
||||
}
|
||||
|
||||
if err = generatePKI(ctx, r); err != nil {
|
||||
if err = waitPKI(ctx, r); err != nil {
|
||||
return fmt.Errorf("failed to generate etcd PKI: %w", err)
|
||||
}
|
||||
|
||||
@ -243,102 +242,16 @@ func (e *Etcd) HealthSettings(runtime.Runtime) *health.Settings {
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func generatePKI(ctx context.Context, r runtime.Runtime) (err error) {
|
||||
if err = os.MkdirAll(constants.EtcdPKIPath, 0o700); err != nil {
|
||||
return err
|
||||
}
|
||||
func waitPKI(ctx context.Context, r runtime.Runtime) error {
|
||||
_, err := r.State().V1Alpha2().Resources().WatchFor(ctx,
|
||||
resource.NewMetadata(etcdresource.NamespaceName, etcdresource.PKIStatusType, etcdresource.PKIID, resource.VersionUndefined),
|
||||
state.WithEventTypes(state.Created, state.Updated),
|
||||
)
|
||||
|
||||
if err = ioutil.WriteFile(constants.KubernetesEtcdCACert, r.Config().Cluster().Etcd().CA().Crt, 0o400); err != nil {
|
||||
return fmt.Errorf("failed to write CA certificate: %w", err)
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile(constants.KubernetesEtcdCAKey, r.Config().Cluster().Etcd().CA().Key, 0o400); err != nil {
|
||||
return fmt.Errorf("failed to write CA key: %w", err)
|
||||
}
|
||||
|
||||
// wait for etcd certificates to be generated in the controller
|
||||
watchCh := make(chan state.Event)
|
||||
|
||||
if err = r.State().V1Alpha2().Resources().Watch(ctx, resource.NewMetadata(secrets.NamespaceName, secrets.EtcdType, secrets.EtcdID, resource.VersionUndefined), watchCh); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var event state.Event
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case event = <-watchCh:
|
||||
}
|
||||
|
||||
if event.Type == state.Created || event.Type == state.Updated {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// wait for additional events with 500ms timeout and absorb new versions of the resource
|
||||
const settleDownTimeout = 500 * time.Millisecond
|
||||
|
||||
timer := time.NewTimer(settleDownTimeout)
|
||||
defer timer.Stop()
|
||||
|
||||
waitLoop:
|
||||
for {
|
||||
select {
|
||||
case event = <-watchCh:
|
||||
if !timer.Stop() {
|
||||
<-timer.C
|
||||
}
|
||||
|
||||
timer.Reset(settleDownTimeout)
|
||||
case <-timer.C:
|
||||
break waitLoop
|
||||
}
|
||||
}
|
||||
|
||||
etcdCerts := event.Resource.(*secrets.Etcd).TypedSpec()
|
||||
|
||||
for _, keypair := range []struct {
|
||||
getter func() *x509.PEMEncodedCertificateAndKey
|
||||
keyPath string
|
||||
certPath string
|
||||
}{
|
||||
{
|
||||
getter: func() *x509.PEMEncodedCertificateAndKey { return etcdCerts.Etcd },
|
||||
keyPath: constants.KubernetesEtcdKey,
|
||||
certPath: constants.KubernetesEtcdCert,
|
||||
},
|
||||
{
|
||||
getter: func() *x509.PEMEncodedCertificateAndKey { return etcdCerts.EtcdPeer },
|
||||
keyPath: constants.KubernetesEtcdPeerKey,
|
||||
certPath: constants.KubernetesEtcdPeerCert,
|
||||
},
|
||||
{
|
||||
getter: func() *x509.PEMEncodedCertificateAndKey { return etcdCerts.EtcdAdmin },
|
||||
keyPath: constants.KubernetesEtcdAdminKey,
|
||||
certPath: constants.KubernetesEtcdAdminCert,
|
||||
},
|
||||
} {
|
||||
if err = ioutil.WriteFile(keypair.keyPath, keypair.getter().Key, 0o400); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile(keypair.certPath, keypair.getter().Crt, 0o400); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return chownRecursive(constants.EtcdPKIPath, constants.EtcdUserID, constants.EtcdUserID)
|
||||
return err
|
||||
}
|
||||
|
||||
func addMember(ctx context.Context, r runtime.Runtime, addrs []string, name string) (*clientv3.MemberListResponse, uint64, error) {
|
||||
// update PKI on each join attempt
|
||||
if err := generatePKI(ctx, r); err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to generate etcd PKI: %w", err)
|
||||
}
|
||||
|
||||
client, err := etcd.NewClientFromControlPlaneIPsNoDiscovery(ctx, r.State().V1Alpha2().Resources())
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
@ -672,7 +585,7 @@ func (e *Etcd) recoverFromSnapshot(hostname, primaryAddr string) error {
|
||||
return fmt.Errorf("error deleting snapshot: %w", err)
|
||||
}
|
||||
|
||||
return chownRecursive(constants.EtcdDataPath, constants.EtcdUserID, constants.EtcdUserID)
|
||||
return filetree.ChownRecursive(constants.EtcdDataPath, constants.EtcdUserID, constants.EtcdUserID)
|
||||
}
|
||||
|
||||
func promoteMember(ctx context.Context, r runtime.Runtime, memberID uint64) error {
|
||||
|
||||
@ -6,11 +6,9 @@ package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
@ -37,18 +35,3 @@ func prepareRootfs(id string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// chownRecursive changes file ownership recursively from the specified root.
|
||||
func chownRecursive(root string, uid, gid uint32) error {
|
||||
return filepath.Walk(root, func(path string, info fs.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if info.Sys().(*syscall.Stat_t).Uid != uid || info.Sys().(*syscall.Stat_t).Gid != gid {
|
||||
return os.Chown(path, int(uid), int(gid))
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
27
pkg/filetree/chown.go
Normal file
27
pkg/filetree/chown.go
Normal file
@ -0,0 +1,27 @@
|
||||
// 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 filetree
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// ChownRecursive changes file ownership recursively from the specified root.
|
||||
func ChownRecursive(root string, uid, gid uint32) error {
|
||||
return filepath.Walk(root, func(path string, info fs.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if info.Sys().(*syscall.Stat_t).Uid != uid || info.Sys().(*syscall.Stat_t).Gid != gid {
|
||||
return os.Chown(path, int(uid), int(gid))
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
6
pkg/filetree/filetree.go
Normal file
6
pkg/filetree/filetree.go
Normal file
@ -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 filetree provides file tree operations.
|
||||
package filetree
|
||||
@ -2,7 +2,7 @@
|
||||
// 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/.
|
||||
|
||||
// Code generated by "deep-copy -type AffiliateSpec -type IdentitySpec -type MemberSpec -type ConfigSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT.
|
||||
// Code generated by "deep-copy -type AffiliateSpec -type ConfigSpec -type IdentitySpec -type MemberSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT.
|
||||
|
||||
package cluster
|
||||
|
||||
@ -28,6 +28,16 @@ func (o AffiliateSpec) DeepCopy() AffiliateSpec {
|
||||
return cp
|
||||
}
|
||||
|
||||
// DeepCopy generates a deep copy of ConfigSpec.
|
||||
func (o ConfigSpec) DeepCopy() ConfigSpec {
|
||||
var cp ConfigSpec = o
|
||||
if o.ServiceEncryptionKey != nil {
|
||||
cp.ServiceEncryptionKey = make([]byte, len(o.ServiceEncryptionKey))
|
||||
copy(cp.ServiceEncryptionKey, o.ServiceEncryptionKey)
|
||||
}
|
||||
return cp
|
||||
}
|
||||
|
||||
// DeepCopy generates a deep copy of IdentitySpec.
|
||||
func (o IdentitySpec) DeepCopy() IdentitySpec {
|
||||
var cp IdentitySpec = o
|
||||
@ -43,13 +53,3 @@ func (o MemberSpec) DeepCopy() MemberSpec {
|
||||
}
|
||||
return cp
|
||||
}
|
||||
|
||||
// DeepCopy generates a deep copy of ConfigSpec.
|
||||
func (o ConfigSpec) DeepCopy() ConfigSpec {
|
||||
var cp ConfigSpec = o
|
||||
if o.ServiceEncryptionKey != nil {
|
||||
cp.ServiceEncryptionKey = make([]byte, len(o.ServiceEncryptionKey))
|
||||
copy(cp.ServiceEncryptionKey, o.ServiceEncryptionKey)
|
||||
}
|
||||
return cp
|
||||
}
|
||||
|
||||
13
pkg/machinery/resources/etcd/deep_copy.generated.go
Normal file
13
pkg/machinery/resources/etcd/deep_copy.generated.go
Normal file
@ -0,0 +1,13 @@
|
||||
// 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/.
|
||||
|
||||
// Code generated by "deep-copy -type PKIStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT.
|
||||
|
||||
package etcd
|
||||
|
||||
// DeepCopy generates a deep copy of PKIStatusSpec.
|
||||
func (o PKIStatusSpec) DeepCopy() PKIStatusSpec {
|
||||
var cp PKIStatusSpec = o
|
||||
return cp
|
||||
}
|
||||
13
pkg/machinery/resources/etcd/etcd.go
Normal file
13
pkg/machinery/resources/etcd/etcd.go
Normal file
@ -0,0 +1,13 @@
|
||||
// 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 etcd provides resources which interface with etcd.
|
||||
package etcd
|
||||
|
||||
import "github.com/cosi-project/runtime/pkg/resource"
|
||||
|
||||
//go:generate deep-copy -type PKIStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .
|
||||
|
||||
// NamespaceName contains resources supporting etcd service.
|
||||
const NamespaceName resource.Namespace = "etcd"
|
||||
32
pkg/machinery/resources/etcd/etcd_test.go
Normal file
32
pkg/machinery/resources/etcd/etcd_test.go
Normal file
@ -0,0 +1,32 @@
|
||||
// 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 etcd_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"github.com/cosi-project/runtime/pkg/state"
|
||||
"github.com/cosi-project/runtime/pkg/state/impl/inmem"
|
||||
"github.com/cosi-project/runtime/pkg/state/impl/namespaced"
|
||||
"github.com/cosi-project/runtime/pkg/state/registry"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/talos-systems/talos/pkg/machinery/resources/etcd"
|
||||
)
|
||||
|
||||
func TestRegisterResource(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
|
||||
resources := state.WrapCore(namespaced.NewState(inmem.Build))
|
||||
resourceRegistry := registry.NewResourceRegistry(resources)
|
||||
|
||||
for _, resource := range []resource.Resource{
|
||||
&etcd.PKIStatus{},
|
||||
} {
|
||||
assert.NoError(t, resourceRegistry.Register(ctx, resource))
|
||||
}
|
||||
}
|
||||
56
pkg/machinery/resources/etcd/pki_status.go
Normal file
56
pkg/machinery/resources/etcd/pki_status.go
Normal file
@ -0,0 +1,56 @@
|
||||
// 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 etcd
|
||||
|
||||
import (
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"github.com/cosi-project/runtime/pkg/resource/meta"
|
||||
"github.com/cosi-project/runtime/pkg/resource/typed"
|
||||
)
|
||||
|
||||
// PKIStatusType is type of PKIStatus resource.
|
||||
const PKIStatusType = resource.Type("PKIStatuses.etcd.talos.dev")
|
||||
|
||||
// PKIID is resource ID for PKIStatus resource for etcd.
|
||||
const PKIID = resource.ID("etcd")
|
||||
|
||||
// PKIStatus resource holds status of rendered secrets.
|
||||
type PKIStatus = typed.Resource[PKIStatusSpec, PKIStatusRD]
|
||||
|
||||
// PKIStatusSpec describes status of rendered secrets.
|
||||
type PKIStatusSpec struct {
|
||||
Ready bool `yaml:"ready"`
|
||||
Version string `yaml:"version"`
|
||||
}
|
||||
|
||||
// NewPKIStatus initializes a PKIStatus resource.
|
||||
func NewPKIStatus(namespace resource.Namespace, id resource.ID) *PKIStatus {
|
||||
return typed.NewResource[PKIStatusSpec, PKIStatusRD](
|
||||
resource.NewMetadata(namespace, PKIStatusType, id, resource.VersionUndefined),
|
||||
PKIStatusSpec{},
|
||||
)
|
||||
}
|
||||
|
||||
// PKIStatusRD provides auxiliary methods for PKIStatus.
|
||||
type PKIStatusRD struct{}
|
||||
|
||||
// ResourceDefinition implements typed.ResourceDefinition interface.
|
||||
func (PKIStatusRD) ResourceDefinition(resource.Metadata, PKIStatusSpec) meta.ResourceDefinitionSpec {
|
||||
return meta.ResourceDefinitionSpec{
|
||||
Type: PKIStatusType,
|
||||
Aliases: []resource.Type{},
|
||||
DefaultNamespace: NamespaceName,
|
||||
PrintColumns: []meta.PrintColumn{
|
||||
{
|
||||
Name: "Ready",
|
||||
JSONPath: "{.ready}",
|
||||
},
|
||||
{
|
||||
Name: "Secrets Version",
|
||||
JSONPath: "{.version}",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -2,22 +2,22 @@
|
||||
// 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/.
|
||||
|
||||
// Code generated by "deep-copy -type ProcessorSpec -type MemoryModuleSpec -type SystemInformationSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT.
|
||||
// Code generated by "deep-copy -type MemoryModuleSpec -type ProcessorSpec -type SystemInformationSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT.
|
||||
|
||||
package hardware
|
||||
|
||||
// DeepCopy generates a deep copy of ProcessorSpec.
|
||||
func (o ProcessorSpec) DeepCopy() ProcessorSpec {
|
||||
var cp ProcessorSpec = o
|
||||
return cp
|
||||
}
|
||||
|
||||
// DeepCopy generates a deep copy of MemoryModuleSpec.
|
||||
func (o MemoryModuleSpec) DeepCopy() MemoryModuleSpec {
|
||||
var cp MemoryModuleSpec = o
|
||||
return cp
|
||||
}
|
||||
|
||||
// DeepCopy generates a deep copy of ProcessorSpec.
|
||||
func (o ProcessorSpec) DeepCopy() ProcessorSpec {
|
||||
var cp ProcessorSpec = o
|
||||
return cp
|
||||
}
|
||||
|
||||
// DeepCopy generates a deep copy of SystemInformationSpec.
|
||||
func (o SystemInformationSpec) DeepCopy() SystemInformationSpec {
|
||||
var cp SystemInformationSpec = o
|
||||
|
||||
@ -8,7 +8,7 @@ import (
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
)
|
||||
|
||||
//go:generate deep-copy -type ProcessorSpec -type MemoryModuleSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .
|
||||
//go:generate deep-copy -type MemoryModuleSpec -type ProcessorSpec -type SystemInformationSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .
|
||||
|
||||
// NamespaceName contains resources related to hardware as a whole.
|
||||
const NamespaceName resource.Namespace = "hardware"
|
||||
|
||||
@ -112,6 +112,14 @@ func (o KubernetesRootSpec) DeepCopy() KubernetesRootSpec {
|
||||
*cp.Endpoint.User = *o.Endpoint.User
|
||||
}
|
||||
}
|
||||
if o.LocalEndpoint != nil {
|
||||
cp.LocalEndpoint = new(url.URL)
|
||||
*cp.LocalEndpoint = *o.LocalEndpoint
|
||||
if o.LocalEndpoint.User != nil {
|
||||
cp.LocalEndpoint.User = new(url.Userinfo)
|
||||
*cp.LocalEndpoint.User = *o.LocalEndpoint.User
|
||||
}
|
||||
}
|
||||
if o.CertSANs != nil {
|
||||
cp.CertSANs = make([]string, len(o.CertSANs))
|
||||
copy(cp.CertSANs, o.CertSANs)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user