Adjust Nudge configuration to match the specification (#9519)
Related to #9013 this adjusts the Nudge configuration to match the spec.
This commit is contained in:
@@ -1262,7 +1262,9 @@ Requires `mdm.macos_updates.deadline` to be set.
|
||||
|
||||
##### mdm.macos_updates.deadline
|
||||
|
||||
A deadline in the form `YYYY-MM-DD`. Hosts that belong to no team and are enrolled into Fleet's MDM won't be able to dismiss the Nudge window once this deadline is past.
|
||||
A deadline in the form `YYYY-MM-DD`. The exact deadline time is at 04:00:00 (UTC-8).
|
||||
|
||||
Hosts that belong to no team and are enrolled into Fleet's MDM won't be able to dismiss the Nudge window once this deadline is past.
|
||||
|
||||
Requires `mdm.macos_updates.minimum_version` to be set.
|
||||
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
package fleet
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// NudgeConfig represents a subset of the [full Nudge configuration][0] that we
|
||||
// want to override.
|
||||
//
|
||||
// [0]: https://github.com/macadmins/nudge/wiki
|
||||
type NudgeConfig struct {
|
||||
OSVersionRequirements []nudgeOSVersionRequirements `json:"osVersionRequirements"`
|
||||
UserInterface nudgeUserInterface `json:"userInterface"`
|
||||
UserExperience nudgeUserExperience `json:"userExperience"`
|
||||
UpdateElements []nudgeUpdateElements `json:"updateElements"`
|
||||
}
|
||||
|
||||
type nudgeAboutUpdateURLs struct {
|
||||
Language string `json:"_language"`
|
||||
AboutUpdateURL string `json:"aboutUpdateURL"`
|
||||
}
|
||||
|
||||
type nudgeOSVersionRequirements struct {
|
||||
RequiredInstallationDate time.Time `json:"requiredInstallationDate"`
|
||||
RequiredMinimumOSVersion string `json:"requiredMinimumOSVersion"`
|
||||
AboutUpdateURLs []nudgeAboutUpdateURLs `json:"aboutUpdateURLs"`
|
||||
}
|
||||
|
||||
type nudgeUserInterface struct {
|
||||
SimpleMode bool `json:"simpleMode"`
|
||||
ShowDeferralCount bool `json:"showDeferralCount"`
|
||||
}
|
||||
|
||||
type nudgeUserExperience struct {
|
||||
InitialRefreshCycle int `json:"initialRefreshCycle"`
|
||||
ApproachingRefreshCycle int `json:"approachingRefreshCycle"`
|
||||
ImminentRefreshCycle int `json:"imminentRefreshCycle"`
|
||||
ElapsedRefreshCycle int `json:"elapsedRefreshCycle"`
|
||||
}
|
||||
|
||||
type nudgeUpdateElements struct {
|
||||
Language string `json:"_language"`
|
||||
ActionButtonText string `json:"actionButtonText"`
|
||||
MainHeader string `json:"mainHeader"`
|
||||
}
|
||||
|
||||
func NewNudgeConfig(macOSUpdates MacOSUpdates) (*NudgeConfig, error) {
|
||||
deadline, err := time.Parse("2006-01-02", macOSUpdates.Deadline)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Per the spec, the exact deadline time is arbitrarily chosen to be
|
||||
// 04:00:00 (UTC-8) until we allow users to customize it.
|
||||
//
|
||||
// See https://github.com/fleetdm/fleet/issues/9013 for more details.
|
||||
localizedDeadline := time.Date(deadline.Year(), deadline.Month(), deadline.Day(), 4, 0, 0, 0, time.UTC)
|
||||
|
||||
return &NudgeConfig{
|
||||
OSVersionRequirements: []nudgeOSVersionRequirements{{
|
||||
RequiredInstallationDate: localizedDeadline,
|
||||
RequiredMinimumOSVersion: macOSUpdates.MinimumVersion,
|
||||
AboutUpdateURLs: []nudgeAboutUpdateURLs{{
|
||||
Language: "en",
|
||||
AboutUpdateURL: "https://fleetdm.com/docs/using-fleet/mobile-device-management#macos-updates",
|
||||
}},
|
||||
}},
|
||||
UserInterface: nudgeUserInterface{
|
||||
SimpleMode: true,
|
||||
ShowDeferralCount: false,
|
||||
},
|
||||
UserExperience: nudgeUserExperience{
|
||||
/* Initially, we show Nudge once every 24 hours */
|
||||
InitialRefreshCycle: 86400,
|
||||
/*
|
||||
* Related to approachingWindowTime (72 hours before deadline by default)
|
||||
* we still want to show the window once every 24 hours.
|
||||
*/
|
||||
ApproachingRefreshCycle: 86400,
|
||||
/*
|
||||
* Related to imminentWindowTime (24 hours before deadline by default)
|
||||
* we want to show the window once every 2 hours.
|
||||
*/
|
||||
ImminentRefreshCycle: 7200,
|
||||
/*
|
||||
* Related to elapsedWindowTime (once the deadline is past)
|
||||
* we want to show the window once every hour.
|
||||
*/
|
||||
ElapsedRefreshCycle: 3600,
|
||||
},
|
||||
UpdateElements: []nudgeUpdateElements{{
|
||||
Language: "en",
|
||||
ActionButtonText: "Update",
|
||||
MainHeader: "Your device requires an update",
|
||||
}},
|
||||
}, nil
|
||||
}
|
||||
@@ -12,6 +12,6 @@ type OrbitConfigNotifications struct {
|
||||
type OrbitConfig struct {
|
||||
Flags json.RawMessage `json:"command_line_startup_flags,omitempty"`
|
||||
Extensions json.RawMessage `json:"extensions,omitempty"`
|
||||
NudgeConfig json.RawMessage `json:"nudge_config,omitempty"`
|
||||
NudgeConfig *NudgeConfig `json:"nudge_config,omitempty"`
|
||||
Notifications OrbitConfigNotifications `json:"notifications,omitempty"`
|
||||
}
|
||||
|
||||
@@ -2141,18 +2141,10 @@ func (s *integrationEnterpriseTestSuite) TestOrbitConfigNudgeSettings() {
|
||||
|
||||
resp = orbitGetConfigResponse{}
|
||||
s.DoJSON("POST", "/api/fleet/orbit/config", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *h.OrbitNodeKey)), http.StatusOK, &resp)
|
||||
require.JSONEq(
|
||||
t,
|
||||
`{
|
||||
"osVersionRequirements": [
|
||||
{
|
||||
"requiredInstallationDate": "2022-01-04",
|
||||
"requiredMinimumOSVersion": "12.1.3"
|
||||
}
|
||||
]
|
||||
}`,
|
||||
string(resp.NudgeConfig),
|
||||
)
|
||||
wantCfg, err := fleet.NewNudgeConfig(fleet.MacOSUpdates{Deadline: "2022-01-04", MinimumVersion: "12.1.3"})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, wantCfg, resp.NudgeConfig)
|
||||
require.Equal(t, wantCfg.OSVersionRequirements[0].RequiredInstallationDate.String(), "2022-01-04 04:00:00 +0000 UTC")
|
||||
|
||||
// create a team with an empty macos_updates config
|
||||
team, err := s.ds.NewTeam(context.Background(), &fleet.Team{
|
||||
@@ -2170,6 +2162,7 @@ func (s *integrationEnterpriseTestSuite) TestOrbitConfigNudgeSettings() {
|
||||
resp = orbitGetConfigResponse{}
|
||||
s.DoJSON("POST", "/api/fleet/orbit/config", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *h.OrbitNodeKey)), http.StatusOK, &resp)
|
||||
require.Empty(t, resp.NudgeConfig)
|
||||
require.Equal(t, wantCfg.OSVersionRequirements[0].RequiredInstallationDate.String(), "2022-01-04 04:00:00 +0000 UTC")
|
||||
|
||||
// modify the team config, add macos_updates config
|
||||
var tmResp teamResponse
|
||||
@@ -2184,35 +2177,19 @@ func (s *integrationEnterpriseTestSuite) TestOrbitConfigNudgeSettings() {
|
||||
|
||||
resp = orbitGetConfigResponse{}
|
||||
s.DoJSON("POST", "/api/fleet/orbit/config", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *h.OrbitNodeKey)), http.StatusOK, &resp)
|
||||
require.JSONEq(
|
||||
t,
|
||||
`{
|
||||
"osVersionRequirements": [
|
||||
{
|
||||
"requiredInstallationDate": "1992-01-01",
|
||||
"requiredMinimumOSVersion": "13.1.1"
|
||||
}
|
||||
]
|
||||
}`,
|
||||
string(resp.NudgeConfig),
|
||||
)
|
||||
wantCfg, err = fleet.NewNudgeConfig(fleet.MacOSUpdates{Deadline: "1992-01-01", MinimumVersion: "13.1.1"})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, wantCfg, resp.NudgeConfig)
|
||||
require.Equal(t, wantCfg.OSVersionRequirements[0].RequiredInstallationDate.String(), "1992-01-01 04:00:00 +0000 UTC")
|
||||
|
||||
// create a new host, still receives the global config
|
||||
h2 := createOrbitEnrolledHost(t, "darwin", "h2", s.ds)
|
||||
resp = orbitGetConfigResponse{}
|
||||
s.DoJSON("POST", "/api/fleet/orbit/config", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *h2.OrbitNodeKey)), http.StatusOK, &resp)
|
||||
require.JSONEq(
|
||||
t,
|
||||
`{
|
||||
"osVersionRequirements": [
|
||||
{
|
||||
"requiredInstallationDate": "2022-01-04",
|
||||
"requiredMinimumOSVersion": "12.1.3"
|
||||
}
|
||||
]
|
||||
}`,
|
||||
string(resp.NudgeConfig),
|
||||
)
|
||||
wantCfg, err = fleet.NewNudgeConfig(fleet.MacOSUpdates{Deadline: "2022-01-04", MinimumVersion: "12.1.3"})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, wantCfg, resp.NudgeConfig)
|
||||
require.Equal(t, wantCfg.OSVersionRequirements[0].RequiredInstallationDate.String(), "2022-01-04 04:00:00 +0000 UTC")
|
||||
}
|
||||
|
||||
// allEqual compares all fields of a struct.
|
||||
|
||||
+8
-19
@@ -1,12 +1,10 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"text/template"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server"
|
||||
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
|
||||
@@ -167,11 +165,12 @@ func (svc *Service) GetOrbitConfig(ctx context.Context) (fleet.OrbitConfig, erro
|
||||
return fleet.OrbitConfig{Notifications: notifs}, err
|
||||
}
|
||||
|
||||
var nudgeConfig bytes.Buffer
|
||||
var nudgeConfig *fleet.NudgeConfig
|
||||
if mdmConfig != nil &&
|
||||
mdmConfig.MacOSUpdates.Deadline != "" &&
|
||||
mdmConfig.MacOSUpdates.MinimumVersion != "" {
|
||||
if err := nudgeConfigTemplate.Execute(&nudgeConfig, mdmConfig.MacOSUpdates); err != nil {
|
||||
nudgeConfig, err = fleet.NewNudgeConfig(mdmConfig.MacOSUpdates)
|
||||
if err != nil {
|
||||
return fleet.OrbitConfig{Notifications: notifs}, err
|
||||
}
|
||||
}
|
||||
@@ -180,7 +179,7 @@ func (svc *Service) GetOrbitConfig(ctx context.Context) (fleet.OrbitConfig, erro
|
||||
Flags: opts.CommandLineStartUpFlags,
|
||||
Extensions: opts.Extensions,
|
||||
Notifications: notifs,
|
||||
NudgeConfig: nudgeConfig.Bytes(),
|
||||
NudgeConfig: nudgeConfig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -196,10 +195,11 @@ func (svc *Service) GetOrbitConfig(ctx context.Context) (fleet.OrbitConfig, erro
|
||||
}
|
||||
}
|
||||
|
||||
var nudgeConfig bytes.Buffer
|
||||
var nudgeConfig *fleet.NudgeConfig
|
||||
if config.MDM.MacOSUpdates.Deadline != "" &&
|
||||
config.MDM.MacOSUpdates.MinimumVersion != "" {
|
||||
if err := nudgeConfigTemplate.Execute(&nudgeConfig, config.MDM.MacOSUpdates); err != nil {
|
||||
nudgeConfig, err = fleet.NewNudgeConfig(config.MDM.MacOSUpdates)
|
||||
if err != nil {
|
||||
return fleet.OrbitConfig{Notifications: notifs}, err
|
||||
}
|
||||
}
|
||||
@@ -208,21 +208,10 @@ func (svc *Service) GetOrbitConfig(ctx context.Context) (fleet.OrbitConfig, erro
|
||||
Flags: opts.CommandLineStartUpFlags,
|
||||
Extensions: opts.Extensions,
|
||||
Notifications: notifs,
|
||||
NudgeConfig: nudgeConfig.Bytes(),
|
||||
NudgeConfig: nudgeConfig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
var nudgeConfigTemplate = template.Must(template.New("").Option("missingkey=error").Parse(`
|
||||
{
|
||||
"osVersionRequirements": [
|
||||
{
|
||||
"requiredInstallationDate": "{{ .Deadline }}",
|
||||
"requiredMinimumOSVersion": "{{ .MinimumVersion }}"
|
||||
}
|
||||
]
|
||||
}
|
||||
`))
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Ping orbit endpoint
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Reference in New Issue
Block a user