diff --git a/listener/template_test.go b/listener/template_test.go index d21c2c949..1a91bcf43 100644 --- a/listener/template_test.go +++ b/listener/template_test.go @@ -33,6 +33,8 @@ func createTempateMsg(t *testing.T, eventName, orgID string, nTemplates int) mqu OrgID: orgID, Description: &description, Date: time.Now(), + Arch: "x86_64", + Version: "8", } } diff --git a/manager/controllers/template_systems.go b/manager/controllers/template_systems.go index 223527a24..d1b004f96 100644 --- a/manager/controllers/template_systems.go +++ b/manager/controllers/template_systems.go @@ -53,42 +53,41 @@ type TemplateSystemsResponse struct { Meta ListMeta `json:"meta"` } -func getTemplateID(c *gin.Context, tx *gorm.DB, account int, uuid string) (int64, error) { - var id int64 +func getTemplate(c *gin.Context, tx *gorm.DB, account int, uuid string) (*models.Template, error) { + var template models.Template if !utils.IsValidUUID(uuid) { err := errors.Errorf("Invalid template uuid: %s", uuid) LogAndRespNotFound(c, err, err.Error()) - return 0, err + return &template, err } err := tx.Model(&models.Template{}). - Select("id"). Where("rh_account_id = ? AND uuid = ?::uuid ", account, uuid). // use Find() not First() otherwise it returns error "no rows found" if uuid is not present - Find(&id).Error + Find(&template).Error if err != nil { LogAndRespError(c, err, "database error") - return 0, err + return &template, err } - if id == 0 { + if template.ID == 0 { err := errors.New("Template not found") LogAndRespNotFound(c, err, err.Error()) - return 0, err + return &template, err } - return id, nil + return &template, nil } func templateSystemsQuery(c *gin.Context, account int, groups map[string]string) (*gorm.DB, Filters, error) { templateUUID := c.Param("template_id") db := middlewares.DBFromContext(c) - templateID, err := getTemplateID(c, db, account, templateUUID) + template, err := getTemplate(c, db, account, templateUUID) if err != nil { // respose set in getTemplateID() return nil, nil, err } query := database.Systems(db, account, groups). - Where("sp.template_id = ?", templateID). + Where("sp.template_id = ?", template.ID). Select(templateSystemSelect) filters, err := ParseAllFilters(c, TemplateSystemOpts) diff --git a/manager/controllers/template_systems_update.go b/manager/controllers/template_systems_update.go index 02618cdb7..0af223e21 100644 --- a/manager/controllers/template_systems_update.go +++ b/manager/controllers/template_systems_update.go @@ -1,6 +1,7 @@ package controllers import ( + "app/base/database" "app/base/models" "app/base/utils" "app/manager/config" @@ -8,6 +9,8 @@ import ( "fmt" "net/http" + errors2 "errors" + "github.com/pkg/errors" "gorm.io/gorm" @@ -44,13 +47,13 @@ func TemplateSystemsUpdateHandler(c *gin.Context) { } db := middlewares.DBFromContext(c) - templateID, err := getTemplateID(c, db, account, templateUUID) + template, err := getTemplate(c, db, account, templateUUID) if err != nil { // respose set in getTemplateID() return } - err = assignTemplateSystems(c, db, account, &templateID, req.Systems, groups) + err = assignTemplateSystems(c, db, account, template, req.Systems, groups) if err != nil { return } @@ -62,7 +65,7 @@ func TemplateSystemsUpdateHandler(c *gin.Context) { c.Status(http.StatusOK) } -func assignTemplateSystems(c *gin.Context, db *gorm.DB, accountID int, templateID *int64, +func assignTemplateSystems(c *gin.Context, db *gorm.DB, accountID int, template *models.Template, inventoryIDs []string, groups map[string]string) error { if len(inventoryIDs) == 0 { err := errors.New(InvalidInventoryIDsErr) @@ -88,6 +91,18 @@ func assignTemplateSystems(c *gin.Context, db *gorm.DB, accountID int, templateI return err } + if err := templateArchVersionMatch(db, inventoryIDs, template, accountID, groups); err != nil { + msg := fmt.Sprintf("Incompatible template and system version or architecture: %s", err.Error()) + LogAndRespBadRequest(c, err, msg) + return err + } + + // if we want to unassign system from template, we need to set template_id=null + var templateID *int64 + if template != nil && template.ID != 0 { + templateID = &template.ID + } + tx = tx.Model(models.SystemPlatform{}). Where("rh_account_id = ? AND inventory_id IN (?::uuid)", accountID, inventoryIDs). @@ -109,3 +124,28 @@ func assignTemplateSystems(c *gin.Context, db *gorm.DB, accountID int, templateI } return nil } + +func templateArchVersionMatch( + db *gorm.DB, inventoryIDs []string, template *models.Template, acc int, groups map[string]string, +) error { + var sysArchVersions = []struct { + InventoryID string + Arch string + Version string + }{} + var err error + database.Systems(db, acc, groups). + Select("ih.id as inventory_id, ih.system_profile->'operating_system'->>'major' as version, sp.arch as arch"). + Where("id in (?)", inventoryIDs).Find(&sysArchVersions) + + for _, sys := range sysArchVersions { + if sys.Version != template.Version && sys.Arch != template.Arch { + if err == nil { + err = fmt.Errorf("template arch: %s, version: %s", template.Arch, template.Version) + } + systemErr := fmt.Errorf("system uuid: %s, arch: %s, version: %s", sys.InventoryID, sys.Arch, sys.Version) + err = errors2.Join(err, systemErr) + } + } + return err +}