Consul is a distributed, highly available, and data center aware solution to connect and configure applications across dynamic, distributed infrastructure.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

363 lines
9.1 KiB

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package expose
import (
"testing"
"github.com/mitchellh/cli"
"github.com/stretchr/testify/require"
"github.com/hashicorp/consul/agent"
"github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/testrpc"
)
func TestConnectExpose(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")
}
t.Parallel()
a := agent.NewTestAgent(t, ``)
client := a.Client()
defer a.Shutdown()
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
{
ui := cli.NewMockUi()
c := New(ui)
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-service=foo",
"-ingress-gateway=ingress",
"-port=8888",
"-protocol=tcp",
}
code := c.Run(args)
if code != 0 {
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())
}
}
// Make sure the config entry and intention have been created.
entry, _, err := client.ConfigEntries().Get(api.IngressGateway, "ingress", nil)
require.NoError(t, err)
ns := entry.(*api.IngressGatewayConfigEntry).Namespace
ap := entry.(*api.IngressGatewayConfigEntry).Partition
expected := &api.IngressGatewayConfigEntry{
Kind: api.IngressGateway,
Name: "ingress",
Namespace: ns,
Partition: ap,
Listeners: []api.IngressListener{
{
Port: 8888,
Protocol: "tcp",
Services: []api.IngressService{
{
Name: "foo",
Namespace: ns,
Partition: ap,
},
},
},
},
}
expected.CreateIndex = entry.GetCreateIndex()
expected.ModifyIndex = entry.GetModifyIndex()
require.Equal(t, expected, entry)
ixns, _, err := client.Connect().Intentions(nil)
require.NoError(t, err)
require.Len(t, ixns, 1)
require.Equal(t, "ingress", ixns[0].SourceName)
require.Equal(t, "foo", ixns[0].DestinationName)
// Run the command again with a different port, make sure the config entry
// is updated while intentions are unmodified.
{
ui := cli.NewMockUi()
c := New(ui)
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-service=foo",
"-ingress-gateway=ingress",
"-port=7777",
"-protocol=tcp",
}
code := c.Run(args)
if code != 0 {
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())
}
expected.Listeners = append(expected.Listeners, api.IngressListener{
Port: 7777,
Protocol: "tcp",
Services: []api.IngressService{
{
Name: "foo",
Namespace: ns,
Partition: ap,
},
},
})
// Make sure the config entry/intention weren't affected.
entry, _, err = client.ConfigEntries().Get(api.IngressGateway, "ingress", nil)
require.NoError(t, err)
expected.ModifyIndex = entry.GetModifyIndex()
require.Equal(t, expected, entry)
ixns, _, err = client.Connect().Intentions(nil)
require.NoError(t, err)
require.Len(t, ixns, 1)
require.Equal(t, "ingress", ixns[0].SourceName)
require.Equal(t, "foo", ixns[0].DestinationName)
}
// Run the command again with a conflicting protocol, should exit with an error and
// cause no changes to config entry/intentions.
{
ui := cli.NewMockUi()
c := New(ui)
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-service=bar",
"-ingress-gateway=ingress",
"-port=8888",
"-protocol=http",
}
code := c.Run(args)
if code != 1 {
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())
}
require.Contains(t, ui.ErrorWriter.String(), `conflicting protocol "tcp"`)
// Make sure the config entry/intention weren't affected.
entry, _, err = client.ConfigEntries().Get(api.IngressGateway, "ingress", nil)
require.NoError(t, err)
require.Equal(t, expected, entry)
ixns, _, err = client.Connect().Intentions(nil)
require.NoError(t, err)
require.Len(t, ixns, 1)
require.Equal(t, "ingress", ixns[0].SourceName)
require.Equal(t, "foo", ixns[0].DestinationName)
}
}
func TestConnectExpose_invalidFlags(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")
}
t.Parallel()
a := agent.NewTestAgent(t, ``)
defer a.Shutdown()
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
t.Run("missing service", func(t *testing.T) {
ui := cli.NewMockUi()
c := New(ui)
args := []string{
"-http-addr=" + a.HTTPAddr(),
}
code := c.Run(args)
if code != 1 {
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())
}
require.Contains(t, ui.ErrorWriter.String(), "A service name must be given")
})
t.Run("missing gateway", func(t *testing.T) {
ui := cli.NewMockUi()
c := New(ui)
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-service=foo",
}
code := c.Run(args)
if code != 1 {
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())
}
require.Contains(t, ui.ErrorWriter.String(), "An ingress gateway service must be given")
})
t.Run("missing port", func(t *testing.T) {
ui := cli.NewMockUi()
c := New(ui)
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-service=foo",
"-ingress-gateway=ingress",
}
code := c.Run(args)
if code != 1 {
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())
}
require.Contains(t, ui.ErrorWriter.String(), "A port must be provided")
})
}
func TestConnectExpose_existingConfig(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")
}
t.Parallel()
a := agent.NewTestAgent(t, ``)
client := a.Client()
defer a.Shutdown()
// Create some service config entries to set their protocol.
for _, service := range []string{"bar", "zoo"} {
_, _, err := client.ConfigEntries().Set(&api.ServiceConfigEntry{
Kind: "service-defaults",
Name: service,
Protocol: "http",
}, nil)
require.NoError(t, err)
}
// Create an existing ingress config entry with some services.
ingressConf := &api.IngressGatewayConfigEntry{
Kind: api.IngressGateway,
Name: "ingress",
Listeners: []api.IngressListener{
{
Port: 8888,
Protocol: "tcp",
Services: []api.IngressService{
{
Name: "foo",
},
},
},
{
Port: 9999,
Protocol: "http",
Services: []api.IngressService{
{
Name: "bar",
},
},
},
},
}
_, _, err := client.ConfigEntries().Set(ingressConf, nil)
require.NoError(t, err)
// Add a service on a new port.
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
{
ui := cli.NewMockUi()
c := New(ui)
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-service=baz",
"-ingress-gateway=ingress",
"-port=10000",
"-protocol=tcp",
}
code := c.Run(args)
if code != 0 {
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())
}
// Make sure the ingress config was updated and existing services preserved.
entry, _, err := client.ConfigEntries().Get(api.IngressGateway, "ingress", nil)
require.NoError(t, err)
entryConf := entry.(*api.IngressGatewayConfigEntry)
ingressConf.Listeners = append(ingressConf.Listeners, api.IngressListener{
Port: 10000,
Protocol: "tcp",
Services: []api.IngressService{
{
Name: "baz",
},
},
})
ingressConf.Partition = entryConf.Partition
ingressConf.Namespace = entryConf.Namespace
for i, listener := range ingressConf.Listeners {
listener.Services[0].Namespace = entryConf.Listeners[i].Services[0].Namespace
listener.Services[0].Partition = entryConf.Listeners[i].Services[0].Partition
}
ingressConf.CreateIndex = entry.GetCreateIndex()
ingressConf.ModifyIndex = entry.GetModifyIndex()
require.Equal(t, ingressConf, entry)
}
// Add an service on a port shared with an existing listener.
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
{
ui := cli.NewMockUi()
c := New(ui)
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-service=zoo",
"-ingress-gateway=ingress",
"-port=9999",
"-protocol=http",
"-host=foo.com",
"-host=foo.net",
}
code := c.Run(args)
if code != 0 {
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())
}
// Make sure the ingress config was updated and existing services preserved.
entry, _, err := client.ConfigEntries().Get(api.IngressGateway, "ingress", nil)
require.NoError(t, err)
entryConf := entry.(*api.IngressGatewayConfigEntry)
ingressConf.Listeners[1].Services = append(ingressConf.Listeners[1].Services, api.IngressService{
Name: "zoo",
Namespace: entryConf.Listeners[1].Services[1].Namespace,
Partition: entryConf.Listeners[1].Services[1].Partition,
Hosts: []string{"foo.com", "foo.net"},
})
ingressConf.CreateIndex = entry.GetCreateIndex()
ingressConf.ModifyIndex = entry.GetModifyIndex()
require.Equal(t, ingressConf, entry)
}
// Update the bar service and add a custom host.
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
{
ui := cli.NewMockUi()
c := New(ui)
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-service=bar",
"-ingress-gateway=ingress",
"-port=9999",
"-protocol=http",
"-host=bar.com",
}
code := c.Run(args)
if code != 0 {
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())
}
// Make sure the ingress config was updated and existing services preserved.
entry, _, err := client.ConfigEntries().Get(api.IngressGateway, "ingress", nil)
require.NoError(t, err)
ingressConf.Listeners[1].Services[0].Hosts = []string{"bar.com"}
ingressConf.CreateIndex = entry.GetCreateIndex()
ingressConf.ModifyIndex = entry.GetModifyIndex()
require.Equal(t, ingressConf, entry)
}
}