mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
parent
ca9874ea79
commit
8ad0d59016
6 changed files with 43 additions and 2 deletions
1
changes/21890-vpp-token-error
Normal file
1
changes/21890-vpp-token-error
Normal file
|
|
@ -0,0 +1 @@
|
|||
- Improve messaging for VPP token constraint errors
|
||||
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/nanomdm/mdm"
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
|
|
@ -780,6 +781,7 @@ TEAMLOOP:
|
|||
}
|
||||
|
||||
func (ds *Datastore) UpdateVPPTokenTeams(ctx context.Context, id uint, teams []uint) (*fleet.VPPTokenDB, error) {
|
||||
stmtTeamName := `SELECT name FROM teams WHERE id = ?`
|
||||
stmtRemove := `DELETE FROM vpp_token_teams WHERE vpp_token_id = ?`
|
||||
stmtInsert := `
|
||||
INSERT INTO
|
||||
|
|
@ -858,6 +860,17 @@ func (ds *Datastore) UpdateVPPTokenTeams(ctx context.Context, id uint, teams []u
|
|||
})
|
||||
|
||||
if err != nil {
|
||||
var mysqlErr *mysql.MySQLError
|
||||
// https://dev.mysql.com/doc/mysql-errors/8.4/en/server-error-reference.html#error_er_dup_entry
|
||||
if errors.As(err, &mysqlErr) && IsDuplicate(err) {
|
||||
var dupeTeamID uint
|
||||
var dupeTeamName string
|
||||
fmt.Sscanf(mysqlErr.Message, "Duplicate entry '%d' for", &dupeTeamID)
|
||||
if err := sqlx.GetContext(ctx, ds.reader(ctx), &dupeTeamName, stmtTeamName, dupeTeamID); err != nil {
|
||||
return nil, ctxerr.Wrap(ctx, err, "getting team name for vpp token conflict error")
|
||||
}
|
||||
return nil, ctxerr.Wrap(ctx, fleet.ErrVPPTokenTeamConstraint{Name: dupeTeamName, ID: &dupeTeamID})
|
||||
}
|
||||
return nil, ctxerr.Wrap(ctx, err, "modifying vpp token team associations")
|
||||
}
|
||||
|
||||
|
|
@ -1127,7 +1140,7 @@ func checkVPPNullTeam(ctx context.Context, tx sqlx.ExtContext, currentID *uint,
|
|||
}
|
||||
|
||||
if allTeamsFound && currentID != nil && *currentID != id {
|
||||
return ctxerr.Wrap(ctx, errors.New("All teams token already exists"))
|
||||
return ctxerr.Wrap(ctx, fleet.ErrVPPTokenTeamConstraint{Name: fleet.ReservedNameAllTeams})
|
||||
}
|
||||
|
||||
if nullTeam != fleet.NullTeamNone {
|
||||
|
|
@ -1139,7 +1152,7 @@ func checkVPPNullTeam(ctx context.Context, tx sqlx.ExtContext, currentID *uint,
|
|||
return ctxerr.Wrap(ctx, err, "scanning row in check vpp token null team")
|
||||
}
|
||||
if currentID == nil || *currentID != id {
|
||||
return ctxerr.Errorf(ctx, "vpp token for team %s already exists", nullTeam)
|
||||
return ctxerr.Wrap(ctx, fleet.ErrVPPTokenTeamConstraint{Name: nullTeam.PrettyName()})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -981,8 +981,10 @@ func testVPPTokensCRUD(t *testing.T, ds *Datastore) {
|
|||
assert.Error(t, err)
|
||||
_, err = ds.UpdateVPPTokenTeams(ctx, tokBadConstraint.ID, []uint{team.ID})
|
||||
assert.Error(t, err)
|
||||
assert.ErrorContains(t, err, "\"Kritters\" team already has a VPP token.")
|
||||
_, err = ds.UpdateVPPTokenTeams(ctx, tokBadConstraint.ID, []uint{0})
|
||||
assert.Error(t, err)
|
||||
assert.ErrorContains(t, err, "\"No team\" team already has a VPP token.")
|
||||
|
||||
toks, err = ds.ListVPPTokens(ctx)
|
||||
assert.NoError(t, err)
|
||||
|
|
|
|||
|
|
@ -801,6 +801,17 @@ const (
|
|||
NullTeamNoTeam NullTeamType = "noteam"
|
||||
)
|
||||
|
||||
func (n NullTeamType) PrettyName() string {
|
||||
switch n {
|
||||
case NullTeamAllTeams:
|
||||
return ReservedNameAllTeams
|
||||
case NullTeamNoTeam:
|
||||
return ReservedNameNoTeam
|
||||
default:
|
||||
return string(n)
|
||||
}
|
||||
}
|
||||
|
||||
type AppleDevice int
|
||||
|
||||
const (
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package fleet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
|
@ -67,3 +68,12 @@ type VPPAppStatusSummary struct {
|
|||
// Failed is the number of hosts that have the VPP app installation failed.
|
||||
Failed uint `json:"failed" db:"failed"`
|
||||
}
|
||||
|
||||
type ErrVPPTokenTeamConstraint struct {
|
||||
Name string
|
||||
ID *uint
|
||||
}
|
||||
|
||||
func (e ErrVPPTokenTeamConstraint) Error() string {
|
||||
return fmt.Sprintf("Error: %q team already has a VPP token. Each team can only have one VPP token.", e.Name)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -557,6 +557,10 @@ func (svc *Service) ModifyAppConfig(ctx context.Context, p []byte, applyOpts fle
|
|||
if appConfig.MDM.VolumePurchasingProgram.Set && appConfig.MDM.VolumePurchasingProgram.Valid {
|
||||
for tokenID, tokenTeams := range vppAssignments {
|
||||
if _, err := svc.ds.UpdateVPPTokenTeams(ctx, tokenID, tokenTeams); err != nil {
|
||||
var errTokConstraint fleet.ErrVPPTokenTeamConstraint
|
||||
if errors.As(err, &errTokConstraint) {
|
||||
return nil, ctxerr.Wrap(ctx, fleet.NewUserMessageError(errTokConstraint, http.StatusConflict))
|
||||
}
|
||||
return nil, ctxerr.Wrap(ctx, err, "saving ABM token assignments")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue