Add os to NodeListStub struct. (#12497)
* Add os to NodeListStub struct. Signed-off-by: Shishir Mahajan <smahajan@roblox.com> * Add os as a query param to /v1/nodes. Signed-off-by: Shishir Mahajan <smahajan@roblox.com> * Add test: os as a query param to /v1/nodes. Signed-off-by: Shishir Mahajan <smahajan@roblox.com>
This commit is contained in:
parent
826d9d47f9
commit
f5121d261e
|
@ -906,6 +906,7 @@ func (v *StatValue) String() string {
|
|||
type NodeListStub struct {
|
||||
Address string
|
||||
ID string
|
||||
Attributes map[string]string `json:",omitempty"`
|
||||
Datacenter string
|
||||
Name string
|
||||
NodeClass string
|
||||
|
|
|
@ -18,15 +18,24 @@ func (s *HTTPServer) NodesRequest(resp http.ResponseWriter, req *http.Request) (
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
args.Fields = &structs.NodeStubFields{}
|
||||
// Parse resources field selection
|
||||
resources, err := parseBool(req, "resources")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resources != nil {
|
||||
args.Fields = &structs.NodeStubFields{
|
||||
Resources: *resources,
|
||||
}
|
||||
args.Fields.Resources = *resources
|
||||
}
|
||||
|
||||
// Parse OS
|
||||
os, err := parseBool(req, "os")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if os != nil {
|
||||
args.Fields.OS = *os
|
||||
}
|
||||
|
||||
var out structs.NodeListResponse
|
||||
|
@ -38,6 +47,7 @@ func (s *HTTPServer) NodesRequest(resp http.ResponseWriter, req *http.Request) (
|
|||
if out.Nodes == nil {
|
||||
out.Nodes = make([]*structs.NodeListStub, 0)
|
||||
}
|
||||
|
||||
return out.Nodes, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -119,6 +119,70 @@ func TestHTTP_NodesPrefixList(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestHTTP_NodesOSList(t *testing.T) {
|
||||
ci.Parallel(t)
|
||||
httpTest(t, nil, func(s *TestAgent) {
|
||||
ids := []string{
|
||||
"12345670-abcd-efab-cdef-123456789abc",
|
||||
"12345671-aaaa-efab-cdef-123456789abc",
|
||||
}
|
||||
oss := []string{
|
||||
"ubuntu",
|
||||
"centos",
|
||||
}
|
||||
for i := 0; i < 2; i++ {
|
||||
// Create the node
|
||||
node := mock.Node()
|
||||
node.ID = ids[i]
|
||||
node.Attributes["os.name"] = oss[i]
|
||||
args := structs.NodeRegisterRequest{
|
||||
Node: node,
|
||||
WriteRequest: structs.WriteRequest{Region: "global"},
|
||||
}
|
||||
var resp structs.NodeUpdateResponse
|
||||
if err := s.Agent.RPC("Node.Register", &args, &resp); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Make the HTTP request
|
||||
req, err := http.NewRequest("GET", "/v1/nodes?prefix=123456&os=true", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
respW := httptest.NewRecorder()
|
||||
|
||||
// Make the request
|
||||
obj, err := s.Server.NodesRequest(respW, req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Check for the index
|
||||
if respW.Header().Get("X-Nomad-Index") == "" {
|
||||
t.Fatalf("missing index")
|
||||
}
|
||||
if respW.Header().Get("X-Nomad-KnownLeader") != "true" {
|
||||
t.Fatalf("missing known leader")
|
||||
}
|
||||
if respW.Header().Get("X-Nomad-LastContact") == "" {
|
||||
t.Fatalf("missing last contact")
|
||||
}
|
||||
|
||||
// Check the nodes attributes
|
||||
nodes := obj.([]*structs.NodeListStub)
|
||||
if len(nodes) != 2 {
|
||||
t.Fatalf("bad: %#v", nodes)
|
||||
}
|
||||
|
||||
for index, node := range nodes {
|
||||
if node.Attributes["os.name"] != oss[index] {
|
||||
t.Fatalf("Expected: %s, Got: %s", oss[index], node.Attributes["os.name"])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestHTTP_NodeForceEval(t *testing.T) {
|
||||
ci.Parallel(t)
|
||||
httpTest(t, nil, func(s *TestAgent) {
|
||||
|
|
|
@ -173,8 +173,13 @@ func (c *NodeStatusCommand) Run(args []string) int {
|
|||
return 1
|
||||
}
|
||||
|
||||
var q *api.QueryOptions
|
||||
if c.os {
|
||||
q = &api.QueryOptions{Params: map[string]string{"os": "true"}}
|
||||
}
|
||||
|
||||
// Query the node info
|
||||
nodes, _, err := client.Nodes().List(nil)
|
||||
nodes, _, err := client.Nodes().List(q)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error querying node status: %s", err))
|
||||
return 1
|
||||
|
@ -231,24 +236,14 @@ func (c *NodeStatusCommand) Run(args []string) int {
|
|||
out[0] += "|Running Allocs"
|
||||
}
|
||||
|
||||
queryOptions := &api.QueryOptions{AllowStale: true}
|
||||
var nodeInfo *api.Node
|
||||
|
||||
for i, node := range nodes {
|
||||
if c.os {
|
||||
nodeInfo, _, err = client.Nodes().Info(node.ID, queryOptions)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error getting node info: %s", err))
|
||||
return 1
|
||||
}
|
||||
}
|
||||
out[i+1] = fmt.Sprintf("%s|%s|%s|%s",
|
||||
limit(node.ID, c.length),
|
||||
node.Datacenter,
|
||||
node.Name,
|
||||
node.NodeClass)
|
||||
if c.os {
|
||||
out[i+1] += fmt.Sprintf("|%s", nodeInfo.Attributes["os.name"])
|
||||
out[i+1] += fmt.Sprintf("|%s", node.Attributes["os.name"])
|
||||
}
|
||||
if c.verbose {
|
||||
out[i+1] += fmt.Sprintf("|%s|%s",
|
||||
|
|
|
@ -2215,6 +2215,13 @@ func (n *Node) Stub(fields *NodeStubFields) *NodeListStub {
|
|||
s.NodeResources = n.NodeResources
|
||||
s.ReservedResources = n.ReservedResources
|
||||
}
|
||||
|
||||
// Fetch key attributes from the main Attributes map.
|
||||
if fields.OS {
|
||||
m := make(map[string]string)
|
||||
m["os.name"] = n.Attributes["os.name"]
|
||||
s.Attributes = m
|
||||
}
|
||||
}
|
||||
|
||||
return s
|
||||
|
@ -2225,6 +2232,7 @@ func (n *Node) Stub(fields *NodeStubFields) *NodeListStub {
|
|||
type NodeListStub struct {
|
||||
Address string
|
||||
ID string
|
||||
Attributes map[string]string `json:",omitempty"`
|
||||
Datacenter string
|
||||
Name string
|
||||
NodeClass string
|
||||
|
@ -2245,6 +2253,7 @@ type NodeListStub struct {
|
|||
// NodeStubFields defines which fields are included in the NodeListStub.
|
||||
type NodeStubFields struct {
|
||||
Resources bool
|
||||
OS bool
|
||||
}
|
||||
|
||||
// Resources is used to define the resources available
|
||||
|
|
|
@ -34,6 +34,9 @@ The table below shows this endpoint's support for
|
|||
- `resources` `(bool: false)` - Specifies whether or not to include the
|
||||
`NodeResources` and `ReservedResources` fields in the response.
|
||||
|
||||
- `os` `(bool: false)` - Specifies whether or not to include special attributes
|
||||
such as operating system name in the response.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```shell-session
|
||||
|
@ -46,12 +49,20 @@ $ curl \
|
|||
http://localhost:4646/v1/nodes?prefix=f7476465
|
||||
```
|
||||
|
||||
```shell-session
|
||||
$ curl \
|
||||
http://localhost:4646/v1/nodes?os=true
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"Address": "10.138.0.5",
|
||||
"Attributes": {
|
||||
"os.name": "ubuntu"
|
||||
},
|
||||
"CreateIndex": 6,
|
||||
"Datacenter": "dc1",
|
||||
"Drain": false,
|
||||
|
|
Loading…
Reference in New Issue