14807: Add "kill instance" management API.
authorTom Clegg <tclegg@veritasgenetics.com>
Tue, 19 Mar 2019 17:40:10 +0000 (13:40 -0400)
committerTom Clegg <tclegg@veritasgenetics.com>
Wed, 20 Mar 2019 19:27:04 +0000 (15:27 -0400)
Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tclegg@veritasgenetics.com>

lib/dispatchcloud/dispatcher.go
lib/dispatchcloud/worker/pool.go

index adf1028b35fe16ab13afbfcb4f0c91672ec17849..9245d5de30928e038da47172dd526cb6d5ca3b8a 100644 (file)
@@ -39,6 +39,7 @@ type pool interface {
        scheduler.WorkerPool
        Instances() []worker.InstanceView
        SetIdleBehavior(cloud.InstanceID, worker.IdleBehavior) error
+       KillInstance(id cloud.InstanceID, reason string) error
        Stop()
 }
 
@@ -147,6 +148,7 @@ func (disp *dispatcher) initialize() {
                mux.HandlerFunc("POST", "/arvados/v1/dispatch/instances/hold", disp.apiInstanceHold)
                mux.HandlerFunc("POST", "/arvados/v1/dispatch/instances/drain", disp.apiInstanceDrain)
                mux.HandlerFunc("POST", "/arvados/v1/dispatch/instances/run", disp.apiInstanceRun)
+               mux.HandlerFunc("POST", "/arvados/v1/dispatch/instances/kill", disp.apiInstanceKill)
                metricsH := promhttp.HandlerFor(disp.reg, promhttp.HandlerOpts{
                        ErrorLog: disp.logger,
                })
@@ -212,6 +214,20 @@ func (disp *dispatcher) apiInstanceRun(w http.ResponseWriter, r *http.Request) {
        disp.apiInstanceIdleBehavior(w, r, worker.IdleBehaviorRun)
 }
 
+// Management API: shutdown/destroy specified instance now.
+func (disp *dispatcher) apiInstanceKill(w http.ResponseWriter, r *http.Request) {
+       id := cloud.InstanceID(r.FormValue("instance_id"))
+       if id == "" {
+               httpserver.Error(w, "instance_id parameter not provided", http.StatusBadRequest)
+               return
+       }
+       err := disp.pool.KillInstance(id, "via management API: "+r.FormValue("reason"))
+       if err != nil {
+               httpserver.Error(w, err.Error(), http.StatusNotFound)
+               return
+       }
+}
+
 func (disp *dispatcher) apiInstanceIdleBehavior(w http.ResponseWriter, r *http.Request, want worker.IdleBehavior) {
        id := cloud.InstanceID(r.FormValue("instance_id"))
        if id == "" {
index 81a658535ea593a7a0a0c2d9231fd66f3055bdbd..014ab93bfe9c7289bcd99286379a3a26bbc38b18 100644 (file)
@@ -691,6 +691,18 @@ func (wp *Pool) Instances() []InstanceView {
        return r
 }
 
+// KillInstance destroys a cloud VM instance. It returns an error if
+// the given instance does not exist.
+func (wp *Pool) KillInstance(id cloud.InstanceID, reason string) error {
+       wkr, ok := wp.workers[id]
+       if !ok {
+               return errors.New("instance not found")
+       }
+       wkr.logger.WithField("Reason", reason).Info("shutting down")
+       wkr.shutdown()
+       return nil
+}
+
 func (wp *Pool) setup() {
        wp.creating = map[string]createCall{}
        wp.exited = map[string]time.Time{}