File size: 2,628 Bytes
b110593
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
//                           _       _
// __      _____  __ ___   ___  __ _| |_ ___
// \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
//  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
//   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
//
//  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
//
//  CONTACT: [email protected]
//

package clusterapi

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"regexp"

	"github.com/weaviate/weaviate/entities/models"
	entschema "github.com/weaviate/weaviate/entities/schema"
	"github.com/weaviate/weaviate/entities/verbosity"
)

type nodesManager interface {
	GetNodeStatus(ctx context.Context, className, output string) (*models.NodeStatus, error)
}

type nodes struct {
	nodesManager nodesManager
	auth         auth
}

func NewNodes(manager nodesManager, auth auth) *nodes {
	return &nodes{nodesManager: manager, auth: auth}
}

var (
	regxNodes      = regexp.MustCompile(`/status`)
	regxNodesClass = regexp.MustCompile(`/status/(` + entschema.ClassNameRegexCore + `)`)
)

func (s *nodes) Nodes() http.Handler {
	return s.auth.handleFunc(s.nodesHandler())
}

func (s *nodes) nodesHandler() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		path := r.URL.Path
		switch {
		case regxNodes.MatchString(path) || regxNodesClass.MatchString(path):
			if r.Method != http.MethodGet {
				msg := fmt.Sprintf("/nodes api path %q not found", path)
				http.Error(w, msg, http.StatusMethodNotAllowed)
				return
			}

			s.incomingNodeStatus().ServeHTTP(w, r)
			return
		default:
			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
			return
		}
	}
}

func (s *nodes) incomingNodeStatus() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer r.Body.Close()

		var className string

		args := regxNodesClass.FindStringSubmatch(r.URL.Path)
		if len(args) == 3 {
			className = args[2]
		}

		output := verbosity.OutputMinimal
		out, found := r.URL.Query()["output"]
		if found && len(out) > 0 {
			output = out[0]
		}

		nodeStatus, err := s.nodesManager.GetNodeStatus(r.Context(), className, output)
		if err != nil {
			http.Error(w, "/nodes fulfill request: "+err.Error(),
				http.StatusBadRequest)
			return
		}

		if nodeStatus == nil {
			w.WriteHeader(http.StatusNotFound)
			return
		}

		nodeStatusBytes, err := json.Marshal(nodeStatus)
		if err != nil {
			http.Error(w, "/nodes marshal response: "+err.Error(),
				http.StatusInternalServerError)
		}

		w.Write(nodeStatusBytes)
	})
}