Resolver
All checks were successful
continuous-integration/drone/push Build is passing

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 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 // Find discoveries by their labels
func (l *LobbyClient) FindByLabels(labels server.Labels) ([]server.Discovery, error) { func (l *LobbyClient) FindByLabels(labels server.Labels) ([]server.Discovery, error) {
l.init() l.init()

View File

@ -14,6 +14,7 @@ func Usage() {
flag.Usage() flag.Usage()
fmt.Println("") fmt.Println("")
fmt.Println("Commands:") 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(" 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 returns list of all registered discovery packets")
fmt.Println(" discoveries labels [LABEL] ... returns list of all registered discovery packets with given labels (OR)") 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] { 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": case "discoveries":
var discoveries []server.Discovery var discoveries []server.Discovery
var err error var err error

View File

@ -28,6 +28,20 @@ func listHandler(c echo.Context) error {
return c.JSONPretty(200, discoveries, " ") 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 { func prometheusHandler(c echo.Context) error {
name := c.Param("name") name := c.Param("name")

View File

@ -204,7 +204,6 @@ func main() {
if err != nil { if err != nil {
log.Printf("discovery changed error: %v", err) log.Printf("discovery changed error: %v", err)
} }
// If config.Register is false this instance won't be registered with other nodes // If config.Register is false this instance won't be registered with other nodes
if config.Register { if config.Register {
// This is background process that sends the message // This is background process that sends the message
@ -225,7 +224,6 @@ func main() {
} else { } else {
log.Println("standalone mode, I won't register myself") log.Println("standalone mode, I won't register myself")
} }
// -------- // --------
// REST API // REST API
// -------- // --------
@ -237,10 +235,10 @@ func main() {
} }
e.Use(middleware.Logger()) e.Use(middleware.Logger())
e.Use(middleware.Recover()) e.Use(middleware.Recover())
// Routes // Routes
if !config.DisableAPI { if !config.DisableAPI {
e.GET("/", listHandler) e.GET("/", listHandler)
e.GET("/v1/resolve", resolveHandler)
e.GET("/v1/discovery", getIdentificationHandler) e.GET("/v1/discovery", getIdentificationHandler)
e.GET("/v1/discoveries", listHandler) e.GET("/v1/discoveries", listHandler)
e.POST("/v1/labels", addLabelsHandler) e.POST("/v1/labels", addLabelsHandler)
@ -251,7 +249,6 @@ func main() {
// ------------------------------ // ------------------------------
// Termination signals processing // Termination signals processing
// ------------------------------ // ------------------------------
signals := make(chan os.Signal, 1) signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
@ -267,7 +264,6 @@ func main() {
} }
e.Shutdown(context.TODO()) e.Shutdown(context.TODO())
}(e, config) }(e, config)
// Start server // 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. // 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)))) 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{} 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+":") trimmed := strings.TrimPrefix(label.String(), "prometheus:"+name+":")
parts := strings.SplitN(trimmed, ":", 2) parts := strings.SplitN(trimmed, ":", 2)
if len(parts) == 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 // packet is somehow different than the localone. This can be used to trigger
// some action in the local machine. // some action in the local machine.
func discoveryChange(discovery server.Discovery) error { func discoveryChange(discovery server.Discovery) error {
if len(config.Callback) > 0 {
changeDetectedChannel <- true changeDetectedChannel <- true
}
return nil return nil
} }

View File

@ -45,9 +45,9 @@ func (d *Discovery) Bytes() ([]byte, error) {
return data, err 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". // 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{} labels := Labels{}
for _, label := range d.Labels { for _, label := range d.Labels {
if strings.HasPrefix(label.String(), prefix) { 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") assert.False(t, discovery.IsAlive(), "discovery not suppose to be alive")
discovery.LastCheck = now 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 assert.Equal(t, nil, discovery.Validate()) // TODO: This needs more love
content, err := json.Marshal(&discovery) content, err := json.Marshal(&discovery)