Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit bcda6c7

Browse files
authoredMar 14, 2025··
Add bootstrap support for AutoUpdateConfig/AutoUpdateVersion resources (#51904) (#53049)
* Add bootstrap support for AutoUpdateConfig/AutoUpdateVersion * Add support for `applyResources` Reduce nested switch for bootstrap new type of resources * Transform test to table test to check same resources for both `bootstrapResources` and `applyResources`
1 parent a75b022 commit bcda6c7

File tree

6 files changed

+175
-2
lines changed

6 files changed

+175
-2
lines changed
 

‎lib/auth/autoupdate/autoupdatev1/service.go

+29
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ type ServiceConfig struct {
5555
Emitter apievents.Emitter
5656
}
5757

58+
// Backend interface for manipulating AutoUpdate resources.
59+
type Backend interface {
60+
services.AutoUpdateService
61+
}
62+
5863
// Service implements the gRPC API layer for the AutoUpdate.
5964
type Service struct {
6065
autoupdate.UnimplementedAutoUpdateServiceServer
@@ -212,6 +217,18 @@ func (s *Service) UpsertAutoUpdateConfig(ctx context.Context, req *autoupdate.Up
212217
return config, trace.Wrap(err)
213218
}
214219

220+
// UpsertAutoUpdateConfig creates a new AutoUpdateConfig or forcefully updates an existing AutoUpdateConfig.
221+
// This is a function rather than a method so that it can be used by the gRPC service
222+
// and the auth server init code when dealing with resources to be applied at startup.
223+
func UpsertAutoUpdateConfig(
224+
ctx context.Context,
225+
backend Backend,
226+
config *autoupdate.AutoUpdateConfig,
227+
) (*autoupdate.AutoUpdateConfig, error) {
228+
out, err := backend.UpsertAutoUpdateConfig(ctx, config)
229+
return out, trace.Wrap(err)
230+
}
231+
215232
// DeleteAutoUpdateConfig deletes AutoUpdateConfig singleton.
216233
func (s *Service) DeleteAutoUpdateConfig(ctx context.Context, req *autoupdate.DeleteAutoUpdateConfigRequest) (*emptypb.Empty, error) {
217234
authCtx, err := s.authorizer.Authorize(ctx)
@@ -390,6 +407,18 @@ func (s *Service) UpsertAutoUpdateVersion(ctx context.Context, req *autoupdate.U
390407
return autoUpdateVersion, trace.Wrap(err)
391408
}
392409

410+
// UpsertAutoUpdateVersion creates a new AutoUpdateVersion or forcefully updates an existing AutoUpdateVersion.
411+
// This is a function rather than a method so that it can be used by the gRPC service
412+
// and the auth server init code when dealing with resources to be applied at startup.
413+
func UpsertAutoUpdateVersion(
414+
ctx context.Context,
415+
backend Backend,
416+
version *autoupdate.AutoUpdateVersion,
417+
) (*autoupdate.AutoUpdateVersion, error) {
418+
out, err := backend.UpsertAutoUpdateVersion(ctx, version)
419+
return out, trace.Wrap(err)
420+
}
421+
393422
// DeleteAutoUpdateVersion deletes AutoUpdateVersion singleton.
394423
func (s *Service) DeleteAutoUpdateVersion(ctx context.Context, req *autoupdate.DeleteAutoUpdateVersionRequest) (*emptypb.Empty, error) {
395424
authCtx, err := s.authorizer.Authorize(ctx)

‎lib/auth/init.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,13 @@ import (
3838
"github.com/gravitational/teleport"
3939
"github.com/gravitational/teleport/api/client/proto"
4040
apidefaults "github.com/gravitational/teleport/api/defaults"
41+
autoupdatev1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1"
4142
"github.com/gravitational/teleport/api/types"
4243
apievents "github.com/gravitational/teleport/api/types/events"
4344
"github.com/gravitational/teleport/lib"
4445
"github.com/gravitational/teleport/lib/ai"
4546
"github.com/gravitational/teleport/lib/ai/embedding"
47+
"github.com/gravitational/teleport/lib/auth/autoupdate/autoupdatev1"
4648
"github.com/gravitational/teleport/lib/auth/keystore"
4749
"github.com/gravitational/teleport/lib/auth/migration"
4850
"github.com/gravitational/teleport/lib/auth/native"
@@ -1133,13 +1135,23 @@ func migrateRemoteClusters(ctx context.Context, asrv *Server) error {
11331135
func applyResources(ctx context.Context, service *Services, resources []types.Resource) error {
11341136
var err error
11351137
for _, resource := range resources {
1136-
switch r := resource.(type) {
1138+
// Unwrap "new style" resources.
1139+
// We always want to switch over the underlying type.
1140+
var res any = resource
1141+
if w, ok := res.(interface{ Unwrap() types.Resource153 }); ok {
1142+
res = w.Unwrap()
1143+
}
1144+
switch r := res.(type) {
11371145
case types.ProvisionToken:
11381146
err = service.Provisioner.UpsertToken(ctx, r)
11391147
case types.ClusterNetworkingConfig:
11401148
err = service.ClusterConfiguration.SetClusterNetworkingConfig(ctx, r)
11411149
case types.AuthPreference:
11421150
err = service.ClusterConfiguration.SetAuthPreference(ctx, r)
1151+
case *autoupdatev1pb.AutoUpdateConfig:
1152+
_, err = autoupdatev1.UpsertAutoUpdateConfig(ctx, service, r)
1153+
case *autoupdatev1pb.AutoUpdateVersion:
1154+
_, err = autoupdatev1.UpsertAutoUpdateVersion(ctx, service, r)
11431155
default:
11441156
return trace.NotImplemented("cannot apply resource of type %T", resource)
11451157
}

‎lib/auth/init_test.go

+52
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"github.com/google/uuid"
3434
"github.com/gravitational/trace"
3535
"github.com/jonboulle/clockwork"
36+
"github.com/stretchr/testify/assert"
3637
"github.com/stretchr/testify/mock"
3738
"github.com/stretchr/testify/require"
3839
"golang.org/x/crypto/ssh"
@@ -1766,3 +1767,54 @@ func TestTeleportProcessAuthVersionUpgradeCheck(t *testing.T) {
17661767
})
17671768
}
17681769
}
1770+
1771+
// TestInitWithAutoUpdateResources verifies that auth init support bootstrapping and apply
1772+
// `AutoUpdateConfig` and `AutoUpdateVersion` resources as well as unmarshalling them from
1773+
// yaml configuration.
1774+
func TestInitWithAutoUpdateResources(t *testing.T) {
1775+
t.Parallel()
1776+
1777+
const autoUpdateConfigYAML = `kind: autoupdate_config
1778+
metadata:
1779+
name: autoupdate-config
1780+
spec:
1781+
tools:
1782+
mode: enabled
1783+
version: v1`
1784+
const autoUpdateVersionYAML = `kind: autoupdate_version
1785+
metadata:
1786+
name: autoupdate-version
1787+
spec:
1788+
tools:
1789+
target_version: 1.2.3
1790+
version: v1`
1791+
1792+
ctx := context.Background()
1793+
resources := []types.Resource{
1794+
resourceFromYAML(t, autoUpdateConfigYAML),
1795+
resourceFromYAML(t, autoUpdateVersionYAML),
1796+
}
1797+
1798+
for _, test := range []struct {
1799+
name string
1800+
fn func(cfg *InitConfig)
1801+
}{
1802+
{name: "bootstrap", fn: func(cfg *InitConfig) { cfg.BootstrapResources = resources }},
1803+
{name: "apply", fn: func(cfg *InitConfig) { cfg.ApplyOnStartupResources = resources }},
1804+
} {
1805+
t.Run(test.name, func(t *testing.T) {
1806+
cfg := setupConfig(t)
1807+
test.fn(&cfg)
1808+
auth, err := Init(ctx, cfg)
1809+
require.NoError(t, err)
1810+
1811+
config, err := auth.GetAutoUpdateConfig(ctx)
1812+
assert.NoError(t, err)
1813+
assert.Equal(t, "enabled", config.GetSpec().GetTools().GetMode())
1814+
1815+
version, err := auth.GetAutoUpdateVersion(ctx)
1816+
assert.NoError(t, err)
1817+
assert.Equal(t, "1.2.3", version.GetSpec().GetTools().GetTargetVersion())
1818+
})
1819+
}
1820+
}

‎lib/services/local/autoupdate.go

+52
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,55 @@ func (s *AutoUpdateService) GetAutoUpdateVersion(ctx context.Context) (*autoupda
156156
func (s *AutoUpdateService) DeleteAutoUpdateVersion(ctx context.Context) error {
157157
return trace.Wrap(s.version.DeleteResource(ctx, types.MetaNameAutoUpdateVersion))
158158
}
159+
160+
// itemFromAutoUpdateConfig generates `backend.Item` from `AutoUpdateConfig` resource type.
161+
func itemFromAutoUpdateConfig(config *autoupdate.AutoUpdateConfig) (*backend.Item, error) {
162+
if err := update.ValidateAutoUpdateConfig(config); err != nil {
163+
return nil, trace.Wrap(err)
164+
}
165+
rev, err := types.GetRevision(config)
166+
if err != nil {
167+
return nil, trace.Wrap(err)
168+
}
169+
value, err := services.MarshalProtoResource[*autoupdate.AutoUpdateConfig](config)
170+
if err != nil {
171+
return nil, trace.Wrap(err)
172+
}
173+
expires, err := types.GetExpiry(config)
174+
if err != nil {
175+
return nil, trace.Wrap(err)
176+
}
177+
item := &backend.Item{
178+
Key: backend.NewKey(autoUpdateConfigPrefix, types.MetaNameAutoUpdateConfig),
179+
Value: value,
180+
Expires: expires,
181+
Revision: rev,
182+
}
183+
return item, nil
184+
}
185+
186+
// itemFromAutoUpdateVersion generates `backend.Item` from `AutoUpdateVersion` resource type.
187+
func itemFromAutoUpdateVersion(version *autoupdate.AutoUpdateVersion) (*backend.Item, error) {
188+
if err := update.ValidateAutoUpdateVersion(version); err != nil {
189+
return nil, trace.Wrap(err)
190+
}
191+
rev, err := types.GetRevision(version)
192+
if err != nil {
193+
return nil, trace.Wrap(err)
194+
}
195+
value, err := services.MarshalProtoResource[*autoupdate.AutoUpdateVersion](version)
196+
if err != nil {
197+
return nil, trace.Wrap(err)
198+
}
199+
expires, err := types.GetExpiry(version)
200+
if err != nil {
201+
return nil, trace.Wrap(err)
202+
}
203+
item := &backend.Item{
204+
Key: backend.NewKey(autoUpdateVersionPrefix, types.MetaNameAutoUpdateVersion),
205+
Value: value,
206+
Expires: expires,
207+
Revision: rev,
208+
}
209+
return item, nil
210+
}

‎lib/services/local/resource.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424

2525
"github.com/gravitational/trace"
2626

27+
autoupdatev1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1"
2728
"github.com/gravitational/teleport/api/types"
2829
"github.com/gravitational/teleport/lib/backend"
2930
"github.com/gravitational/teleport/lib/services"
@@ -82,7 +83,15 @@ func itemsFromResource(resource types.Resource) ([]backend.Item, error) {
8283
var item *backend.Item
8384
var extItems []backend.Item
8485
var err error
85-
switch r := resource.(type) {
86+
87+
// Unwrap "new style" resources.
88+
// We always want to switch over the underlying type.
89+
var res any = resource
90+
if w, ok := res.(types.Resource153Unwrapper); ok {
91+
res = w.Unwrap()
92+
}
93+
94+
switch r := res.(type) {
8695
case types.User:
8796
item, err = itemFromUser(r)
8897
if auth := r.GetLocalAuth(); err == nil && auth != nil {
@@ -108,6 +117,10 @@ func itemsFromResource(resource types.Resource) ([]backend.Item, error) {
108117
item, err = itemFromClusterNetworkingConfig(r)
109118
case types.AuthPreference:
110119
item, err = itemFromAuthPreference(r)
120+
case *autoupdatev1pb.AutoUpdateConfig:
121+
item, err = itemFromAutoUpdateConfig(r)
122+
case *autoupdatev1pb.AutoUpdateVersion:
123+
item, err = itemFromAutoUpdateVersion(r)
111124
default:
112125
return nil, trace.NotImplemented("cannot itemFrom resource of type %T", resource)
113126
}

‎lib/services/resource.go

+15
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"google.golang.org/protobuf/proto"
2929
"google.golang.org/protobuf/types/known/timestamppb"
3030

31+
autoupdatev1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1"
3132
headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1"
3233
"github.com/gravitational/teleport/api/types"
3334
"github.com/gravitational/teleport/lib/utils"
@@ -644,6 +645,20 @@ func init() {
644645
}
645646
return ap, nil
646647
})
648+
RegisterResourceUnmarshaler(types.KindAutoUpdateConfig, func(bytes []byte, option ...MarshalOption) (types.Resource, error) {
649+
c := &autoupdatev1pb.AutoUpdateConfig{}
650+
if err := protojson.Unmarshal(bytes, c); err != nil {
651+
return nil, trace.Wrap(err)
652+
}
653+
return types.Resource153ToLegacy(c), nil
654+
})
655+
RegisterResourceUnmarshaler(types.KindAutoUpdateVersion, func(bytes []byte, option ...MarshalOption) (types.Resource, error) {
656+
v := &autoupdatev1pb.AutoUpdateVersion{}
657+
if err := protojson.Unmarshal(bytes, v); err != nil {
658+
return nil, trace.Wrap(err)
659+
}
660+
return types.Resource153ToLegacy(v), nil
661+
})
647662
}
648663

649664
// CheckAndSetDefaults calls [r.CheckAndSetDefaults] if r implements the method.

0 commit comments

Comments
 (0)
Please sign in to comment.