mirror of
https://github.com/kemko/nomad.git
synced 2026-01-06 18:35:44 +03:00
allocs: Add nomad alloc stop
This adds a `nomad alloc stop` command that can be used to stop and force migrate an allocation to a different node. This is built on top of the AllocUpdateDesiredTransitionRequest and explicitly limits the scope of access to that transition to expose it under the alloc-lifecycle ACL. The API returns the follow up eval that can be used as part of monitoring in the CLI or parsed and used in an external tool.
This commit is contained in:
@@ -42,7 +42,29 @@ func (s *HTTPServer) AllocsRequest(resp http.ResponseWriter, req *http.Request)
|
||||
}
|
||||
|
||||
func (s *HTTPServer) AllocSpecificRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
allocID := strings.TrimPrefix(req.URL.Path, "/v1/allocation/")
|
||||
reqSuffix := strings.TrimPrefix(req.URL.Path, "/v1/allocation/")
|
||||
|
||||
// tokenize the suffix of the path to get the alloc id and find the action
|
||||
// invoked on the alloc id
|
||||
tokens := strings.Split(reqSuffix, "/")
|
||||
if len(tokens) > 2 || len(tokens) < 1 {
|
||||
return nil, CodedError(404, resourceNotFoundErr)
|
||||
}
|
||||
allocID := tokens[0]
|
||||
|
||||
if len(tokens) == 1 {
|
||||
return s.allocGet(allocID, resp, req)
|
||||
}
|
||||
|
||||
switch tokens[1] {
|
||||
case "stop":
|
||||
return s.allocStop(allocID, resp, req)
|
||||
}
|
||||
|
||||
return nil, CodedError(404, resourceNotFoundErr)
|
||||
}
|
||||
|
||||
func (s *HTTPServer) allocGet(allocID string, resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
if req.Method != "GET" {
|
||||
return nil, CodedError(405, ErrInvalidMethod)
|
||||
}
|
||||
@@ -79,8 +101,22 @@ func (s *HTTPServer) AllocSpecificRequest(resp http.ResponseWriter, req *http.Re
|
||||
return alloc, nil
|
||||
}
|
||||
|
||||
func (s *HTTPServer) ClientAllocRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
func (s *HTTPServer) allocStop(allocID string, resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
if !(req.Method == "POST" || req.Method == "PUT") {
|
||||
return nil, CodedError(405, ErrInvalidMethod)
|
||||
}
|
||||
|
||||
sr := &structs.AllocStopRequest{
|
||||
AllocID: allocID,
|
||||
}
|
||||
s.parseWriteRequest(req, &sr.WriteRequest)
|
||||
|
||||
var out structs.AllocStopResponse
|
||||
err := s.agent.RPC("Alloc.Stop", &sr, &out)
|
||||
return &out, err
|
||||
}
|
||||
|
||||
func (s *HTTPServer) ClientAllocRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
reqSuffix := strings.TrimPrefix(req.URL.Path, "/v1/client/allocation/")
|
||||
|
||||
// tokenize the suffix of the path to get the alloc id and find the action
|
||||
|
||||
@@ -394,6 +394,49 @@ func TestHTTP_AllocRestart_ACL(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestHTTP_AllocStop(t *testing.T) {
|
||||
t.Parallel()
|
||||
httpTest(t, nil, func(s *TestAgent) {
|
||||
// Directly manipulate the state
|
||||
state := s.Agent.server.State()
|
||||
alloc := mock.Alloc()
|
||||
require := require.New(t)
|
||||
require.NoError(state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)))
|
||||
|
||||
require.NoError(state.UpsertAllocs(1000, []*structs.Allocation{alloc}))
|
||||
|
||||
{
|
||||
// Make the HTTP request
|
||||
req, err := http.NewRequest("POST", "/v1/allocation/"+alloc.ID+"/stop", nil)
|
||||
require.NoError(err)
|
||||
respW := httptest.NewRecorder()
|
||||
|
||||
// Make the request
|
||||
obj, err := s.Server.AllocSpecificRequest(respW, req)
|
||||
require.NoError(err)
|
||||
|
||||
a := obj.(*structs.AllocStopResponse)
|
||||
require.NotEmpty(a.EvalID, "missing eval")
|
||||
require.NotEmpty(a.Index, "missing index")
|
||||
}
|
||||
|
||||
{
|
||||
// Make the HTTP request
|
||||
req, err := http.NewRequest("POST", "/v1/allocation/"+alloc.ID+"/stop", nil)
|
||||
require.NoError(err)
|
||||
respW := httptest.NewRecorder()
|
||||
|
||||
// Make the request
|
||||
obj, err := s.Server.AllocSpecificRequest(respW, req)
|
||||
require.NoError(err)
|
||||
|
||||
a := obj.(*structs.AllocStopResponse)
|
||||
require.NotEmpty(a.EvalID, "missing eval")
|
||||
require.NotEmpty(a.Index, "missing index")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestHTTP_AllocStats(t *testing.T) {
|
||||
t.Parallel()
|
||||
require := require.New(t)
|
||||
|
||||
Reference in New Issue
Block a user