A module that puts nothing on a machine cannot be assigned to one #22
@@ -431,6 +431,9 @@ func (i *Inventory) Assign(ctx context.Context, nodeName, module string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := i.runsSomewhere(ctx, module); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = i.store.Pool().Exec(ctx,
|
||||
`insert into assignment (node, module) values ($1, $2) on conflict do nothing`,
|
||||
node.ID, module)
|
||||
@@ -871,3 +874,43 @@ func (i *Inventory) Running(ctx context.Context, module string) ([]string, error
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
// runsSomewhere refuses to put a module on a machine when it would put nothing there.
|
||||
//
|
||||
// **Not every thing the mesh builds is a thing a machine runs.** The image every module in the
|
||||
// scripted toolchain is compiled on top of is built, versioned and depended upon like a module, and
|
||||
// is registered as one so the mesh can track all three. It is not one: it declares no resources,
|
||||
// because nothing about it belongs on a machine — its whole purpose is to be the starting point for
|
||||
// other modules' builds.
|
||||
//
|
||||
// Without this, assigning it succeeds, the machine is sent a declaration containing nothing of it,
|
||||
// and everything reports success. The operator has said "run this here" and the mesh has agreed to
|
||||
// something it cannot do. Said at the assignment, which is where somebody is standing.
|
||||
//
|
||||
// A module whose resources are worked out per node declares none here and is still assignable —
|
||||
// that is the point of it — so it is asked about separately rather than caught by the same test.
|
||||
func (i *Inventory) runsSomewhere(ctx context.Context, module string) error {
|
||||
var raw []byte
|
||||
err := i.store.Pool().QueryRow(ctx,
|
||||
`select manifest from module where name = $1`, module).Scan(&raw)
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
// Left to the insert, which already says this and says it the same way everywhere.
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var m catalogue.Manifest
|
||||
if err := json.Unmarshal(raw, &m); err != nil {
|
||||
// Unreadable is not the same as empty. A manifest the mesh cannot parse is a separate
|
||||
// fault and refusing the assignment here would report it as the wrong one.
|
||||
return nil
|
||||
}
|
||||
if m.Computed != "" || len(m.Resources) > 0 {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf(
|
||||
"%s puts nothing on a machine, so there is nothing to assign. It is something this mesh "+
|
||||
"builds and other modules are built on top of, not something a machine runs — "+
|
||||
"`module list` shows what it produces", module)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user