Skip to content

Commit

Permalink
Add autoupdate_agenbt_rollout support
Browse files Browse the repository at this point in the history
  • Loading branch information
hugoShaka committed Nov 26, 2024
1 parent beec948 commit 2c00768
Show file tree
Hide file tree
Showing 6 changed files with 1,104 additions and 107 deletions.
8 changes: 6 additions & 2 deletions api/client/webclient/webclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ import (
"github.com/gravitational/teleport/api/utils/keys"
)

const (
AgentUpdateGroupParameter = "group"
)

// Config specifies information when building requests with the
// webclient.
type Config struct {
Expand Down Expand Up @@ -179,7 +183,7 @@ func Find(cfg *Config) (*PingResponse, error) {
}
if cfg.UpdateGroup != "" {
endpoint.RawQuery = url.Values{
"group": []string{cfg.UpdateGroup},
AgentUpdateGroupParameter: []string{cfg.UpdateGroup},
}.Encode()
}

Expand Down Expand Up @@ -224,7 +228,7 @@ func Ping(cfg *Config) (*PingResponse, error) {
}
if cfg.UpdateGroup != "" {
endpoint.RawQuery = url.Values{
"group": []string{cfg.UpdateGroup},
AgentUpdateGroupParameter: []string{cfg.UpdateGroup},
}.Encode()
}
if cfg.ConnectorName != "" {
Expand Down
97 changes: 11 additions & 86 deletions lib/web/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,16 @@ import (
"google.golang.org/protobuf/types/known/timestamppb"

"github.com/gravitational/teleport"
"github.com/gravitational/teleport/api"
apiclient "github.com/gravitational/teleport/api/client"
"github.com/gravitational/teleport/api/client/proto"
"github.com/gravitational/teleport/api/client/webclient"
"github.com/gravitational/teleport/api/constants"
apidefaults "github.com/gravitational/teleport/api/defaults"
autoupdatepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1"
mfav1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/mfa/v1"
notificationsv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/notifications/v1"
"github.com/gravitational/teleport/api/mfa"
apitracing "github.com/gravitational/teleport/api/observability/tracing"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/types/autoupdate"
apievents "github.com/gravitational/teleport/api/types/events"
"github.com/gravitational/teleport/api/types/installers"
"github.com/gravitational/teleport/api/utils/keys"
Expand Down Expand Up @@ -1073,7 +1070,7 @@ func (h *Handler) bindDefaultEndpoints() {

// Implements the agent version server.
// Channel can contain "/", hence the use of a catch-all parameter
h.GET("/webapi/automaticupgrades/channel/*request", h.WithUnauthenticatedHighLimiter(h.automaticUpgrades))
h.GET("/webapi/automaticupgrades/channel/*request", h.WithUnauthenticatedHighLimiter(h.automaticUpgrades109))

// GET Machine ID bot by name
h.GET("/webapi/sites/:site/machine-id/bot/:name", h.WithClusterAuth(h.getBot))
Expand Down Expand Up @@ -1548,22 +1545,29 @@ func (h *Handler) ping(w http.ResponseWriter, r *http.Request, p httprouter.Para
return nil, trace.Wrap(err)
}

group := r.URL.Query().Get(webclient.AgentUpdateGroupParameter)

return webclient.PingResponse{
Auth: authSettings,
Proxy: *proxyConfig,
ServerVersion: teleport.Version,
MinClientVersion: teleport.MinClientVersion,
ClusterName: h.auth.clusterName,
AutomaticUpgrades: pr.ServerFeatures.GetAutomaticUpgrades(),
AutoUpdate: h.automaticUpdateSettings(r.Context()),
AutoUpdate: h.automaticUpdateSettings184(r.Context(), group, "" /* updater UUID */),
Edition: modules.GetModules().BuildType(),
FIPS: modules.IsBoringBinary(),
}, nil
}

func (h *Handler) find(w http.ResponseWriter, r *http.Request, p httprouter.Params) (interface{}, error) {
group := r.URL.Query().Get(webclient.AgentUpdateGroupParameter)
cacheKey := "find"
if group != "" {
cacheKey += "-" + group
}
// cache the generic answer to avoid doing work for each request
resp, err := utils.FnCacheGet[*webclient.PingResponse](r.Context(), h.findEndpointCache, "find", func(ctx context.Context) (*webclient.PingResponse, error) {
resp, err := utils.FnCacheGet[*webclient.PingResponse](r.Context(), h.findEndpointCache, cacheKey, func(ctx context.Context) (*webclient.PingResponse, error) {
proxyConfig, err := h.cfg.ProxySettings.GetProxySettings(ctx)
if err != nil {
return nil, trace.Wrap(err)
Expand All @@ -1582,7 +1586,7 @@ func (h *Handler) find(w http.ResponseWriter, r *http.Request, p httprouter.Para
ClusterName: h.auth.clusterName,
Edition: modules.GetModules().BuildType(),
FIPS: modules.IsBoringBinary(),
AutoUpdate: h.automaticUpdateSettings(ctx),
AutoUpdate: h.automaticUpdateSettings184(ctx, group, "" /* updater UUID */),
}, nil
})
if err != nil {
Expand All @@ -1591,29 +1595,6 @@ func (h *Handler) find(w http.ResponseWriter, r *http.Request, p httprouter.Para
return resp, nil
}

// TODO: add the request as a parameter when we'll need to modulate the content based on the UUID and group
func (h *Handler) automaticUpdateSettings(ctx context.Context) webclient.AutoUpdateSettings {
autoUpdateConfig, err := h.cfg.AccessPoint.GetAutoUpdateConfig(ctx)
// TODO(vapopov) DELETE IN v18.0.0 check of IsNotImplemented, must be backported to all latest supported versions.
if err != nil && !trace.IsNotFound(err) && !trace.IsNotImplemented(err) {
h.logger.ErrorContext(ctx, "failed to receive AutoUpdateConfig", "error", err)
}

autoUpdateVersion, err := h.cfg.AccessPoint.GetAutoUpdateVersion(ctx)
// TODO(vapopov) DELETE IN v18.0.0 check of IsNotImplemented, must be backported to all latest supported versions.
if err != nil && !trace.IsNotFound(err) && !trace.IsNotImplemented(err) {
h.logger.ErrorContext(ctx, "failed to receive AutoUpdateVersion", "error", err)
}

return webclient.AutoUpdateSettings{
ToolsAutoUpdate: getToolsAutoUpdate(autoUpdateConfig),
ToolsVersion: getToolsVersion(autoUpdateVersion),
AgentUpdateJitterSeconds: DefaultAgentUpdateJitterSeconds,
AgentVersion: getAgentVersion(autoUpdateVersion),
AgentAutoUpdate: agentShouldUpdate(autoUpdateConfig, autoUpdateVersion),
}
}

func (h *Handler) pingWithConnector(w http.ResponseWriter, r *http.Request, p httprouter.Params) (interface{}, error) {
authClient := h.cfg.ProxyClient
connectorName := p.ByName("connector")
Expand Down Expand Up @@ -5205,59 +5186,3 @@ func readEtagFromAppHash(fs http.FileSystem) (string, error) {

return etag, nil
}

func getToolsAutoUpdate(config *autoupdatepb.AutoUpdateConfig) bool {
// If we can't get the AU config or if AUs are not configured, we default to "disabled".
// This ensures we fail open and don't accidentally update agents if something is going wrong.
// If we want to enable AUs by default, it would be better to create a default "autoupdate_config" resource
// than changing this logic.
if config.GetSpec().GetTools() != nil {
return config.GetSpec().GetTools().GetMode() == autoupdate.ToolsUpdateModeEnabled
}
return false
}

func getToolsVersion(version *autoupdatepb.AutoUpdateVersion) string {
// If we can't get the AU version or tools AU version is not specified, we default to the current proxy version.
// This ensures we always advertise a version compatible with the cluster.
if version.GetSpec().GetTools() == nil {
return api.Version
}
return version.GetSpec().GetTools().GetTargetVersion()
}

func getAgentVersion(version *autoupdatepb.AutoUpdateVersion) string {
// If we can't get the AU version or tools AU version is not specified, we default to the current proxy version.
// This ensures we always advertise a version compatible with the cluster.
// TODO: read the version from the autoupdate_agent_rollout when the resource is implemented
if version.GetSpec().GetAgents() == nil {
return api.Version
}

return version.GetSpec().GetAgents().GetTargetVersion()
}

func agentShouldUpdate(config *autoupdatepb.AutoUpdateConfig, version *autoupdatepb.AutoUpdateVersion) bool {
// TODO: read the data from the autoupdate_agent_rollout when the resource is implemented

// If we can't get the AU config or if AUs are not configured, we default to "disabled".
// This ensures we fail open and don't accidentally update agents if something is going wrong.
// If we want to enable AUs by default, it would be better to create a default "autoupdate_config" resource
// than changing this logic.
if config.GetSpec().GetAgents() == nil {
return false
}
if version.GetSpec().GetAgents() == nil {
return false
}
configMode := config.GetSpec().GetAgents().GetMode()
versionMode := version.GetSpec().GetAgents().GetMode()

// We update only if both version and config agent modes are "enabled"
if configMode != autoupdate.AgentsUpdateModeEnabled || versionMode != autoupdate.AgentsUpdateModeEnabled {
return false
}

scheduleName := version.GetSpec().GetAgents().GetSchedule()
return scheduleName == autoupdate.AgentsScheduleImmediate
}
Loading

0 comments on commit 2c00768

Please sign in to comment.