Resolver
continuous-integration/drone/push Build is passing Details

Resolve API endpoint and cli command return list of hostnames
base on given label.
This commit is contained in:
Adam Štrauch 2021-09-20 16:10:52 +02:00
parent 3a7662ef0d
commit 6a1ecb80a1
Signed by: cx
GPG Key ID: 018304FFA8988F8D
8 changed files with 67 additions and 10 deletions

View File

@ -114,6 +114,31 @@ func (l *LobbyClient) GetDiscoveries() ([]server.Discovery, error) {
return discoveries, nil
}
// Resolve returns list of hostnames that have given label
func (l *LobbyClient) Resolve(label server.Label) ([]string, error) {
l.init()
path := fmt.Sprintf("/v1/resolve?label=%s", label.String())
method := "GET"
var hostnames []string
status, body, err := l.call(method, path, "")
if err != nil {
return hostnames, err
}
if status != 200 {
return hostnames, fmt.Errorf("non-200 response: %s", body)
}
err = json.Unmarshal([]byte(body), &hostnames)
if err != nil {
return hostnames, fmt.Errorf("response parsing error: %v", err)
}
return hostnames, nil
}
// Find discoveries by their labels
func (l *LobbyClient) FindByLabels(labels server.Labels) ([]server.Discovery, error) {
l.init()

View File

@ -14,6 +14,7 @@ func Usage() {
flag.Usage()
fmt.Println("")
fmt.Println("Commands:")
fmt.Println(" resolve label returns list of hostnames with given label")
fmt.Println(" discovery returns discovery packet of the server where the client is connected to")
fmt.Println(" discoveries returns list of all registered discovery packets")
fmt.Println(" discoveries labels [LABEL] ... returns list of all registered discovery packets with given labels (OR)")
@ -68,6 +69,25 @@ func main() {
}
switch flag.Args()[0] {
case "resolve":
if len(flag.Args()) == 2 {
hostnames, err := client.Resolve(server.Label(flag.Arg(1)))
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if *jsonOutput {
printJSON(hostnames)
} else {
for _, hostname := range hostnames {
fmt.Println(hostname)
}
}
} else {
Usage()
os.Exit(0)
}
case "discoveries":
var discoveries []server.Discovery
var err error

View File

@ -28,6 +28,20 @@ func listHandler(c echo.Context) error {
return c.JSONPretty(200, discoveries, " ")
}
// resolveHandler returns hostname(s) based on another label
func resolveHandler(c echo.Context) error {
label := c.QueryParam("label") // This is label we will use to filter discovery packets
output := []string{}
discoveries := discoveryStorage.Filter([]string{label})
for _, discovery := range discoveries {
output = append(output, discovery.Hostname)
}
return c.JSONPretty(http.StatusOK, output, " ")
}
func prometheusHandler(c echo.Context) error {
name := c.Param("name")

View File

@ -204,7 +204,6 @@ func main() {
if err != nil {
log.Printf("discovery changed error: %v", err)
}
// If config.Register is false this instance won't be registered with other nodes
if config.Register {
// This is background process that sends the message
@ -225,7 +224,6 @@ func main() {
} else {
log.Println("standalone mode, I won't register myself")
}
// --------
// REST API
// --------
@ -237,10 +235,10 @@ func main() {
}
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// Routes
if !config.DisableAPI {
e.GET("/", listHandler)
e.GET("/v1/resolve", resolveHandler)
e.GET("/v1/discovery", getIdentificationHandler)
e.GET("/v1/discoveries", listHandler)
e.POST("/v1/labels", addLabelsHandler)
@ -251,7 +249,6 @@ func main() {
// ------------------------------
// Termination signals processing
// ------------------------------
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
@ -267,7 +264,6 @@ func main() {
}
e.Shutdown(context.TODO())
}(e, config)
// Start server
// In most cases this will end expectedly so it doesn't make sense to use the echo's approach to treat this message as an error.
e.Logger.Info(e.Start(config.Host + ":" + strconv.Itoa(int(config.Port))))

View File

@ -39,7 +39,7 @@ func preparePrometheusOutput(name string, discoveries []server.Discovery) Promet
labels := map[string]string{}
for _, label := range discovery.FindLabels("prometheus:" + name + ":") {
for _, label := range discovery.FindLabelsByPrefix("prometheus:" + name + ":") {
trimmed := strings.TrimPrefix(label.String(), "prometheus:"+name+":")
parts := strings.SplitN(trimmed, ":", 2)
if len(parts) == 2 {

View File

@ -95,6 +95,8 @@ func discoveryChangeLoop() {
// packet is somehow different than the localone. This can be used to trigger
// some action in the local machine.
func discoveryChange(discovery server.Discovery) error {
changeDetectedChannel <- true
if len(config.Callback) > 0 {
changeDetectedChannel <- true
}
return nil
}

View File

@ -45,9 +45,9 @@ func (d *Discovery) Bytes() ([]byte, error) {
return data, err
}
// FindLabels returns list of labels with given prefix. For example "service:ns" has prefix "service" or "service:".
// FindLabelsByPrefix returns list of labels with given prefix. For example "service:ns" has prefix "service" or "service:".
// It doesn't have to be prefix, but for example "service:test" will match "service:test" and also "service:test2".
func (d *Discovery) FindLabels(prefix string) Labels {
func (d *Discovery) FindLabelsByPrefix(prefix string) Labels {
labels := Labels{}
for _, label := range d.Labels {
if strings.HasPrefix(label.String(), prefix) {

View File

@ -27,7 +27,7 @@ func TestDiscovery(t *testing.T) {
assert.False(t, discovery.IsAlive(), "discovery not suppose to be alive")
discovery.LastCheck = now
assert.Equal(t, Labels{Label("service:test")}, discovery.FindLabels("service"))
assert.Equal(t, Labels{Label("service:test")}, discovery.FindLabelsByPrefix("service"))
assert.Equal(t, nil, discovery.Validate()) // TODO: This needs more love
content, err := json.Marshal(&discovery)