2015-11-14 02:07:35 +00:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
"testing"
|
|
|
|
|
2017-04-29 16:34:02 +00:00
|
|
|
"github.com/hashicorp/consul/testutil/retry"
|
2015-11-14 02:07:35 +00:00
|
|
|
)
|
|
|
|
|
2017-06-30 20:58:55 +00:00
|
|
|
func TestAPI_PreparedQuery(t *testing.T) {
|
2015-11-14 02:07:35 +00:00
|
|
|
t.Parallel()
|
|
|
|
c, s := makeClient(t)
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
// Set up a node and a service.
|
|
|
|
reg := &CatalogRegistration{
|
|
|
|
Datacenter: "dc1",
|
|
|
|
Node: "foobar",
|
|
|
|
Address: "192.168.10.10",
|
2016-08-16 17:30:30 +00:00
|
|
|
TaggedAddresses: map[string]string{
|
|
|
|
"wan": "127.0.0.1",
|
|
|
|
},
|
2017-01-23 23:53:45 +00:00
|
|
|
NodeMeta: map[string]string{"somekey": "somevalue"},
|
2015-11-14 02:07:35 +00:00
|
|
|
Service: &AgentService{
|
|
|
|
ID: "redis1",
|
|
|
|
Service: "redis",
|
|
|
|
Tags: []string{"master", "v1"},
|
Improve Connect with Prepared Queries (#5291)
Given a query like:
```
{
"Name": "tagged-connect-query",
"Service": {
"Service": "foo",
"Tags": ["tag"],
"Connect": true
}
}
```
And a Consul configuration like:
```
{
"services": [
"name": "foo",
"port": 8080,
"connect": { "sidecar_service": {} },
"tags": ["tag"]
]
}
```
If you executed the query it would always turn up with 0 results. This was because the sidecar service was being created without any tags. You could instead make your config look like:
```
{
"services": [
"name": "foo",
"port": 8080,
"connect": { "sidecar_service": {
"tags": ["tag"]
} },
"tags": ["tag"]
]
}
```
However that is a bit redundant for most cases. This PR ensures that the tags and service meta of the parent service get copied to the sidecar service. If there are any tags or service meta set in the sidecar service definition then this copying does not take place. After the changes, the query will now return the expected results.
A second change was made to prepared queries in this PR which is to allow filtering on ServiceMeta just like we allow for filtering on NodeMeta.
2019-02-04 14:36:51 +00:00
|
|
|
Meta: map[string]string{"redis-version": "4.0"},
|
2015-11-14 02:07:35 +00:00
|
|
|
Port: 8000,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
catalog := c.Catalog()
|
2017-05-04 22:52:53 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
2015-11-14 02:07:35 +00:00
|
|
|
if _, err := catalog.Register(reg, nil); err != nil {
|
2017-04-29 16:34:02 +00:00
|
|
|
r.Fatal(err)
|
2015-11-14 02:07:35 +00:00
|
|
|
}
|
|
|
|
if _, _, err := catalog.Node("foobar", nil); err != nil {
|
2017-04-29 16:34:02 +00:00
|
|
|
r.Fatal(err)
|
2015-11-14 02:07:35 +00:00
|
|
|
}
|
2017-04-29 16:34:02 +00:00
|
|
|
})
|
2015-11-14 02:07:35 +00:00
|
|
|
|
|
|
|
// Create a simple prepared query.
|
|
|
|
def := &PreparedQueryDefinition{
|
2016-12-10 19:19:08 +00:00
|
|
|
Name: "test",
|
2015-11-14 02:07:35 +00:00
|
|
|
Service: ServiceQuery{
|
Improve Connect with Prepared Queries (#5291)
Given a query like:
```
{
"Name": "tagged-connect-query",
"Service": {
"Service": "foo",
"Tags": ["tag"],
"Connect": true
}
}
```
And a Consul configuration like:
```
{
"services": [
"name": "foo",
"port": 8080,
"connect": { "sidecar_service": {} },
"tags": ["tag"]
]
}
```
If you executed the query it would always turn up with 0 results. This was because the sidecar service was being created without any tags. You could instead make your config look like:
```
{
"services": [
"name": "foo",
"port": 8080,
"connect": { "sidecar_service": {
"tags": ["tag"]
} },
"tags": ["tag"]
]
}
```
However that is a bit redundant for most cases. This PR ensures that the tags and service meta of the parent service get copied to the sidecar service. If there are any tags or service meta set in the sidecar service definition then this copying does not take place. After the changes, the query will now return the expected results.
A second change was made to prepared queries in this PR which is to allow filtering on ServiceMeta just like we allow for filtering on NodeMeta.
2019-02-04 14:36:51 +00:00
|
|
|
Service: "redis",
|
|
|
|
NodeMeta: map[string]string{"somekey": "somevalue"},
|
|
|
|
ServiceMeta: map[string]string{"redis-version": "4.0"},
|
2015-11-14 02:07:35 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
query := c.PreparedQuery()
|
|
|
|
var err error
|
|
|
|
def.ID, _, err = query.Create(def, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read it back.
|
|
|
|
defs, _, err := query.Get(def.ID, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
if len(defs) != 1 || !reflect.DeepEqual(defs[0], def) {
|
|
|
|
t.Fatalf("bad: %v", defs)
|
|
|
|
}
|
|
|
|
|
|
|
|
// List them all.
|
|
|
|
defs, _, err = query.List(nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
if len(defs) != 1 || !reflect.DeepEqual(defs[0], def) {
|
|
|
|
t.Fatalf("bad: %v", defs)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make an update.
|
|
|
|
def.Name = "my-query"
|
|
|
|
_, err = query.Update(def, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read it back again to verify the update worked.
|
|
|
|
defs, _, err = query.Get(def.ID, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
if len(defs) != 1 || !reflect.DeepEqual(defs[0], def) {
|
|
|
|
t.Fatalf("bad: %v", defs)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Execute by ID.
|
|
|
|
results, _, err := query.Execute(def.ID, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
if len(results.Nodes) != 1 || results.Nodes[0].Node.Node != "foobar" {
|
|
|
|
t.Fatalf("bad: %v", results)
|
|
|
|
}
|
2016-08-16 17:30:30 +00:00
|
|
|
if wan, ok := results.Nodes[0].Node.TaggedAddresses["wan"]; !ok || wan != "127.0.0.1" {
|
|
|
|
t.Fatalf("bad: %v", results)
|
|
|
|
}
|
2015-11-14 02:07:35 +00:00
|
|
|
|
|
|
|
// Execute by name.
|
|
|
|
results, _, err = query.Execute("my-query", nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
if len(results.Nodes) != 1 || results.Nodes[0].Node.Node != "foobar" {
|
|
|
|
t.Fatalf("bad: %v", results)
|
|
|
|
}
|
2016-08-16 17:30:30 +00:00
|
|
|
if wan, ok := results.Nodes[0].Node.TaggedAddresses["wan"]; !ok || wan != "127.0.0.1" {
|
|
|
|
t.Fatalf("bad: %v", results)
|
|
|
|
}
|
2017-04-18 12:02:24 +00:00
|
|
|
if results.Nodes[0].Node.Datacenter != "dc1" {
|
|
|
|
t.Fatalf("bad datacenter: %v", results)
|
|
|
|
}
|
2015-11-14 02:07:35 +00:00
|
|
|
|
2018-04-10 12:28:27 +00:00
|
|
|
// Add new node with failing health check.
|
|
|
|
reg2 := reg
|
|
|
|
reg2.Node = "failingnode"
|
|
|
|
reg2.Check = &AgentCheck{
|
|
|
|
Node: "failingnode",
|
|
|
|
ServiceID: "redis1",
|
|
|
|
ServiceName: "redis",
|
|
|
|
Name: "failingcheck",
|
|
|
|
Status: "critical",
|
|
|
|
}
|
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
if _, err := catalog.Register(reg2, nil); err != nil {
|
|
|
|
r.Fatal(err)
|
|
|
|
}
|
|
|
|
if _, _, err := catalog.Node("failingnode", nil); err != nil {
|
|
|
|
r.Fatal(err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// Execute by ID. Should return only healthy node.
|
|
|
|
results, _, err = query.Execute(def.ID, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
if len(results.Nodes) != 1 || results.Nodes[0].Node.Node != "foobar" {
|
|
|
|
t.Fatalf("bad: %v", results)
|
|
|
|
}
|
|
|
|
if wan, ok := results.Nodes[0].Node.TaggedAddresses["wan"]; !ok || wan != "127.0.0.1" {
|
|
|
|
t.Fatalf("bad: %v", results)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update PQ with ignore rule for the failing check
|
|
|
|
def.Service.IgnoreCheckIDs = []string{"failingcheck"}
|
|
|
|
_, err = query.Update(def, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Execute by ID. Should return BOTH nodes ignoring the failing check.
|
|
|
|
results, _, err = query.Execute(def.ID, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
if len(results.Nodes) != 2 {
|
|
|
|
t.Fatalf("got %d nodes, want 2", len(results.Nodes))
|
|
|
|
}
|
|
|
|
|
2015-11-14 02:07:35 +00:00
|
|
|
// Delete it.
|
|
|
|
_, err = query.Delete(def.ID, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure there are no longer any queries.
|
|
|
|
defs, _, err = query.List(nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
if len(defs) != 0 {
|
|
|
|
t.Fatalf("bad: %v", defs)
|
|
|
|
}
|
|
|
|
}
|