Skip to content

Commit

Permalink
Add bootstrap support for AutoUpdateConfig/AutoUpdateVersion resources (
Browse files Browse the repository at this point in the history
#51904)

* 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`
  • Loading branch information
vapopov authored Feb 8, 2025
1 parent cb07b42 commit 43038e4
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 1 deletion.
32 changes: 32 additions & 0 deletions lib/auth/autoupdate/autoupdatev1/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ type ServiceConfig struct {
Emitter apievents.Emitter
}

// Backend interface for manipulating AutoUpdate resources.
type Backend interface {
services.AutoUpdateService
}

// Service implements the gRPC API layer for the AutoUpdate.
type Service struct {
autoupdate.UnimplementedAutoUpdateServiceServer
Expand Down Expand Up @@ -241,6 +246,21 @@ func (s *Service) UpsertAutoUpdateConfig(ctx context.Context, req *autoupdate.Up
return config, trace.Wrap(err)
}

// UpsertAutoUpdateConfig creates a new AutoUpdateConfig or forcefully updates an existing AutoUpdateConfig.
// This is a function rather than a method so that it can be used by the gRPC service
// and the auth server init code when dealing with resources to be applied at startup.
func UpsertAutoUpdateConfig(
ctx context.Context,
backend Backend,
config *autoupdate.AutoUpdateConfig,
) (*autoupdate.AutoUpdateConfig, error) {
if err := validateServerSideAgentConfig(config); err != nil {
return nil, trace.Wrap(err, "validating config")
}
out, err := backend.UpsertAutoUpdateConfig(ctx, config)
return out, trace.Wrap(err)
}

// DeleteAutoUpdateConfig deletes AutoUpdateConfig singleton.
func (s *Service) DeleteAutoUpdateConfig(ctx context.Context, req *autoupdate.DeleteAutoUpdateConfigRequest) (*emptypb.Empty, error) {
authCtx, err := s.authorizer.Authorize(ctx)
Expand Down Expand Up @@ -435,6 +455,18 @@ func (s *Service) UpsertAutoUpdateVersion(ctx context.Context, req *autoupdate.U
return autoUpdateVersion, trace.Wrap(err)
}

// UpsertAutoUpdateVersion creates a new AutoUpdateVersion or forcefully updates an existing AutoUpdateVersion.
// This is a function rather than a method so that it can be used by the gRPC service
// and the auth server init code when dealing with resources to be applied at startup.
func UpsertAutoUpdateVersion(
ctx context.Context,
backend Backend,
version *autoupdate.AutoUpdateVersion,
) (*autoupdate.AutoUpdateVersion, error) {
out, err := backend.UpsertAutoUpdateVersion(ctx, version)
return out, trace.Wrap(err)
}

// DeleteAutoUpdateVersion deletes AutoUpdateVersion singleton.
func (s *Service) DeleteAutoUpdateVersion(ctx context.Context, req *autoupdate.DeleteAutoUpdateVersionRequest) (*emptypb.Empty, error) {
authCtx, err := s.authorizer.Authorize(ctx)
Expand Down
6 changes: 6 additions & 0 deletions lib/auth/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import (

"github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/client/proto"
autoupdatev1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1"
clusterconfigpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/clusterconfig/v1"
dbobjectimportrulev1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/dbobjectimportrule/v1"
machineidv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1"
Expand All @@ -52,6 +53,7 @@ import (
apievents "github.com/gravitational/teleport/api/types/events"
"github.com/gravitational/teleport/api/utils/keys"
"github.com/gravitational/teleport/lib"
"github.com/gravitational/teleport/lib/auth/autoupdate/autoupdatev1"
"github.com/gravitational/teleport/lib/auth/dbobjectimportrule/dbobjectimportrulev1"
"github.com/gravitational/teleport/lib/auth/keystore"
"github.com/gravitational/teleport/lib/auth/machineid/machineidv1"
Expand Down Expand Up @@ -1443,6 +1445,10 @@ func applyResources(ctx context.Context, service *Services, resources []types.Re
_, err = machineidv1.UpsertBot(ctx, service, r, time.Now(), "system")
case *dbobjectimportrulev1pb.DatabaseObjectImportRule:
_, err = dbobjectimportrulev1.UpsertDatabaseObjectImportRule(ctx, service, r)
case *autoupdatev1pb.AutoUpdateConfig:
_, err = autoupdatev1.UpsertAutoUpdateConfig(ctx, service, r)
case *autoupdatev1pb.AutoUpdateVersion:
_, err = autoupdatev1.UpsertAutoUpdateVersion(ctx, service, r)
default:
return trace.NotImplemented("cannot apply resource of type %T", resource)
}
Expand Down
51 changes: 51 additions & 0 deletions lib/auth/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2283,3 +2283,54 @@ func Test_createPresetDatabaseObjectImportRule(t *testing.T) {
})
}
}

// TestInitWithAutoUpdateResources verifies that auth init support bootstrapping and apply
// `AutoUpdateConfig` and `AutoUpdateVersion` resources as well as unmarshalling them from
// yaml configuration.
func TestInitWithAutoUpdateResources(t *testing.T) {
t.Parallel()

const autoUpdateConfigYAML = `kind: autoupdate_config
metadata:
name: autoupdate-config
spec:
tools:
mode: enabled
version: v1`
const autoUpdateVersionYAML = `kind: autoupdate_version
metadata:
name: autoupdate-version
spec:
tools:
target_version: 1.2.3
version: v1`

ctx := context.Background()
resources := []types.Resource{
resourceFromYAML(t, autoUpdateConfigYAML),
resourceFromYAML(t, autoUpdateVersionYAML),
}

for _, test := range []struct {
name string
fn func(cfg *InitConfig)
}{
{name: "bootstrap", fn: func(cfg *InitConfig) { cfg.BootstrapResources = resources }},
{name: "apply", fn: func(cfg *InitConfig) { cfg.ApplyOnStartupResources = resources }},
} {
t.Run(test.name, func(t *testing.T) {
cfg := setupConfig(t)
test.fn(&cfg)
auth, err := Init(ctx, cfg)
require.NoError(t, err)

config, err := auth.GetAutoUpdateConfig(ctx)
assert.NoError(t, err)
assert.Equal(t, "enabled", config.GetSpec().GetTools().GetMode())

version, err := auth.GetAutoUpdateVersion(ctx)
assert.NoError(t, err)
assert.Equal(t, "1.2.3", version.GetSpec().GetTools().GetTargetVersion())
})
}
}
52 changes: 52 additions & 0 deletions lib/services/local/autoupdate.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,55 @@ func (s *AutoUpdateService) GetAutoUpdateAgentRollout(ctx context.Context) (*aut
func (s *AutoUpdateService) DeleteAutoUpdateAgentRollout(ctx context.Context) error {
return trace.Wrap(s.rollout.DeleteResource(ctx, types.MetaNameAutoUpdateAgentRollout))
}

// itemFromAutoUpdateConfig generates `backend.Item` from `AutoUpdateConfig` resource type.
func itemFromAutoUpdateConfig(config *autoupdate.AutoUpdateConfig) (*backend.Item, error) {
if err := update.ValidateAutoUpdateConfig(config); err != nil {
return nil, trace.Wrap(err)
}
rev, err := types.GetRevision(config)
if err != nil {
return nil, trace.Wrap(err)
}
value, err := services.MarshalProtoResource[*autoupdate.AutoUpdateConfig](config)
if err != nil {
return nil, trace.Wrap(err)
}
expires, err := types.GetExpiry(config)
if err != nil {
return nil, trace.Wrap(err)
}
item := &backend.Item{
Key: backend.NewKey(autoUpdateConfigPrefix).AppendKey(backend.NewKey(types.MetaNameAutoUpdateConfig)),
Value: value,
Expires: expires,
Revision: rev,
}
return item, nil
}

// itemFromAutoUpdateVersion generates `backend.Item` from `AutoUpdateVersion` resource type.
func itemFromAutoUpdateVersion(version *autoupdate.AutoUpdateVersion) (*backend.Item, error) {
if err := update.ValidateAutoUpdateVersion(version); err != nil {
return nil, trace.Wrap(err)
}
rev, err := types.GetRevision(version)
if err != nil {
return nil, trace.Wrap(err)
}
value, err := services.MarshalProtoResource[*autoupdate.AutoUpdateVersion](version)
if err != nil {
return nil, trace.Wrap(err)
}
expires, err := types.GetExpiry(version)
if err != nil {
return nil, trace.Wrap(err)
}
item := &backend.Item{
Key: backend.NewKey(autoUpdateVersionPrefix).AppendKey(backend.NewKey(types.MetaNameAutoUpdateVersion)),
Value: value,
Expires: expires,
Revision: rev,
}
return item, nil
}
15 changes: 14 additions & 1 deletion lib/services/local/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (

"github.com/gravitational/trace"

autoupdatev1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/backend"
"github.com/gravitational/teleport/lib/services"
Expand Down Expand Up @@ -71,7 +72,15 @@ func itemsFromResource(resource types.Resource) ([]backend.Item, error) {
var item *backend.Item
var extItems []backend.Item
var err error
switch r := resource.(type) {

// Unwrap "new style" resources.
// We always want to switch over the underlying type.
var res any = resource
if w, ok := res.(types.Resource153Unwrapper); ok {
res = w.Unwrap()
}

switch r := res.(type) {
case types.User:
item, err = itemFromUser(r)
if auth := r.GetLocalAuth(); err == nil && auth != nil {
Expand All @@ -97,6 +106,10 @@ func itemsFromResource(resource types.Resource) ([]backend.Item, error) {
item, err = itemFromClusterNetworkingConfig(r)
case types.AuthPreference:
item, err = itemFromAuthPreference(r)
case *autoupdatev1pb.AutoUpdateConfig:
item, err = itemFromAutoUpdateConfig(r)
case *autoupdatev1pb.AutoUpdateVersion:
item, err = itemFromAutoUpdateVersion(r)
default:
return nil, trace.NotImplemented("cannot itemFrom resource of type %T", resource)
}
Expand Down
15 changes: 15 additions & 0 deletions lib/services/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"google.golang.org/protobuf/protoadapt"
"google.golang.org/protobuf/types/known/timestamppb"

autoupdatev1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1"
headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1"
machineidv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1"
"github.com/gravitational/teleport/api/types"
Expand Down Expand Up @@ -715,6 +716,20 @@ func init() {
}
return types.Resource153ToLegacy(b), nil
})
RegisterResourceUnmarshaler(types.KindAutoUpdateConfig, func(bytes []byte, option ...MarshalOption) (types.Resource, error) {
c := &autoupdatev1pb.AutoUpdateConfig{}
if err := protojson.Unmarshal(bytes, c); err != nil {
return nil, trace.Wrap(err)
}
return types.Resource153ToLegacy(c), nil
})
RegisterResourceUnmarshaler(types.KindAutoUpdateVersion, func(bytes []byte, option ...MarshalOption) (types.Resource, error) {
v := &autoupdatev1pb.AutoUpdateVersion{}
if err := protojson.Unmarshal(bytes, v); err != nil {
return nil, trace.Wrap(err)
}
return types.Resource153ToLegacy(v), nil
})
}

// CheckAndSetDefaults calls [r.CheckAndSetDefaults] if r implements the method.
Expand Down

0 comments on commit 43038e4

Please sign in to comment.