2016-01-13 18:19:53 +00:00
|
|
|
package nomad
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
|
2022-12-01 15:05:15 +00:00
|
|
|
"github.com/armon/go-metrics"
|
|
|
|
"github.com/hashicorp/go-hclog"
|
|
|
|
"github.com/hashicorp/go-memdb"
|
2018-09-15 23:23:13 +00:00
|
|
|
|
2017-10-09 03:53:50 +00:00
|
|
|
"github.com/hashicorp/nomad/acl"
|
2016-01-13 18:19:53 +00:00
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
|
|
)
|
|
|
|
|
2016-01-19 19:45:51 +00:00
|
|
|
// Periodic endpoint is used for periodic job interactions
|
2016-01-13 18:19:53 +00:00
|
|
|
type Periodic struct {
|
2018-09-15 23:23:13 +00:00
|
|
|
srv *Server
|
2022-12-01 15:05:15 +00:00
|
|
|
ctx *RPCContext
|
|
|
|
logger hclog.Logger
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewPeriodicEndpoint(srv *Server, ctx *RPCContext) *Periodic {
|
|
|
|
return &Periodic{srv: srv, ctx: ctx, logger: srv.logger.Named("periodic")}
|
2016-01-13 18:19:53 +00:00
|
|
|
}
|
|
|
|
|
2016-01-19 19:45:51 +00:00
|
|
|
// Force is used to force a new instance of a periodic job
|
2016-01-13 18:19:53 +00:00
|
|
|
func (p *Periodic) Force(args *structs.PeriodicForceRequest, reply *structs.PeriodicForceResponse) error {
|
2023-01-25 19:33:06 +00:00
|
|
|
|
|
|
|
authErr := p.srv.Authenticate(p.ctx, args)
|
2016-01-13 18:19:53 +00:00
|
|
|
if done, err := p.srv.forward("Periodic.Force", args, args, reply); done {
|
|
|
|
return err
|
|
|
|
}
|
2023-01-25 21:37:24 +00:00
|
|
|
p.srv.MeasureRPCRate("periodic", structs.RateMetricWrite, args)
|
2023-01-25 19:33:06 +00:00
|
|
|
if authErr != nil {
|
|
|
|
return structs.ErrPermissionDenied
|
|
|
|
}
|
2016-01-13 18:19:53 +00:00
|
|
|
defer metrics.MeasureSince([]string{"nomad", "periodic", "force"}, time.Now())
|
|
|
|
|
2017-10-09 03:53:50 +00:00
|
|
|
// Check for write-job permissions
|
2023-01-25 19:33:06 +00:00
|
|
|
if aclObj, err := p.srv.ResolveACL(args); err != nil {
|
2017-10-09 03:53:50 +00:00
|
|
|
return err
|
2020-10-27 20:33:01 +00:00
|
|
|
} else if aclObj != nil && !aclObj.AllowNsOp(args.RequestNamespace(), acl.NamespaceCapabilityDispatchJob) && !aclObj.AllowNsOp(args.RequestNamespace(), acl.NamespaceCapabilitySubmitJob) {
|
2017-10-09 03:53:50 +00:00
|
|
|
return structs.ErrPermissionDenied
|
|
|
|
}
|
|
|
|
|
2016-01-13 18:19:53 +00:00
|
|
|
// Validate the arguments
|
|
|
|
if args.JobID == "" {
|
|
|
|
return fmt.Errorf("missing job ID for evaluation")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup the job
|
|
|
|
snap, err := p.srv.fsm.State().Snapshot()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-02-08 04:31:23 +00:00
|
|
|
|
|
|
|
ws := memdb.NewWatchSet()
|
2017-09-07 23:56:15 +00:00
|
|
|
job, err := snap.JobByID(ws, args.RequestNamespace(), args.JobID)
|
2016-01-13 18:19:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if job == nil {
|
|
|
|
return fmt.Errorf("job not found")
|
|
|
|
}
|
|
|
|
|
|
|
|
if !job.IsPeriodic() {
|
|
|
|
return fmt.Errorf("can't force launch non-periodic job")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Force run the job.
|
2023-03-27 13:38:48 +00:00
|
|
|
eval, err := p.srv.periodicDispatcher.ForceEval(args.RequestNamespace(), job.ID)
|
2016-01-13 18:19:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("force launch for job %q failed: %v", job.ID, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
reply.EvalID = eval.ID
|
|
|
|
reply.EvalCreateIndex = eval.CreateIndex
|
|
|
|
reply.Index = eval.CreateIndex
|
|
|
|
return nil
|
|
|
|
}
|