Merge pull request #11566 from hashicorp/ap/ingress
OSS Backport: Allow ingress gateways to target other partitions
This commit is contained in:
commit
f4cbde4086
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:improvement
|
||||||
|
connect: **(Enterprise only)** Allow ingress gateways to target services in another partition
|
||||||
|
```
|
|
@ -155,7 +155,7 @@ func makeUpstream(g *structs.GatewayService) structs.Upstream {
|
||||||
upstream := structs.Upstream{
|
upstream := structs.Upstream{
|
||||||
DestinationName: g.Service.Name,
|
DestinationName: g.Service.Name,
|
||||||
DestinationNamespace: g.Service.NamespaceOrDefault(),
|
DestinationNamespace: g.Service.NamespaceOrDefault(),
|
||||||
DestinationPartition: g.Gateway.PartitionOrDefault(),
|
DestinationPartition: g.Service.PartitionOrDefault(),
|
||||||
LocalBindPort: g.Port,
|
LocalBindPort: g.Port,
|
||||||
IngressHosts: g.Hosts,
|
IngressHosts: g.Hosts,
|
||||||
// Pass the protocol that was configured on the ingress listener in order
|
// Pass the protocol that was configured on the ingress listener in order
|
||||||
|
@ -232,6 +232,7 @@ func (s *handlerIngressGateway) generateIngressDNSSANs(snap *ConfigSnapshot) []s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(partitions): How should these be updated for partitions?
|
||||||
for ns := range namespaces {
|
for ns := range namespaces {
|
||||||
// The default namespace is special cased in DNS resolution, so special
|
// The default namespace is special cased in DNS resolution, so special
|
||||||
// case it here.
|
// case it here.
|
||||||
|
|
|
@ -266,10 +266,7 @@ func (e *IngressGatewayConfigEntry) Validate() error {
|
||||||
|
|
||||||
declaredHosts := make(map[string]bool)
|
declaredHosts := make(map[string]bool)
|
||||||
serviceNames := make(map[ServiceID]struct{})
|
serviceNames := make(map[ServiceID]struct{})
|
||||||
for i, s := range listener.Services {
|
for _, s := range listener.Services {
|
||||||
if err := validateInnerEnterpriseMeta(&s.EnterpriseMeta, &e.EnterpriseMeta); err != nil {
|
|
||||||
return fmt.Errorf("services[%d]: %w", i, err)
|
|
||||||
}
|
|
||||||
sn := NewServiceName(s.Name, &s.EnterpriseMeta)
|
sn := NewServiceName(s.Name, &s.EnterpriseMeta)
|
||||||
if err := s.RequestHeaders.Validate(listener.Protocol); err != nil {
|
if err := s.RequestHeaders.Validate(listener.Protocol); err != nil {
|
||||||
return fmt.Errorf("request headers %s (service %q on listener on port %d)", err, sn.String(), listener.Port)
|
return fmt.Errorf("request headers %s (service %q on listener on port %d)", err, sn.String(), listener.Port)
|
||||||
|
|
|
@ -103,12 +103,14 @@ type IngressService struct {
|
||||||
// using a "tcp" listener.
|
// using a "tcp" listener.
|
||||||
Hosts []string
|
Hosts []string
|
||||||
|
|
||||||
// Referencing other partitions is not supported.
|
|
||||||
|
|
||||||
// Namespace is the namespace where the service is located.
|
// Namespace is the namespace where the service is located.
|
||||||
// Namespacing is a Consul Enterprise feature.
|
// Namespacing is a Consul Enterprise feature.
|
||||||
Namespace string `json:",omitempty"`
|
Namespace string `json:",omitempty"`
|
||||||
|
|
||||||
|
// Partition is the partition where the service is located.
|
||||||
|
// Partitioning is a Consul Enterprise feature.
|
||||||
|
Partition string `json:",omitempty"`
|
||||||
|
|
||||||
// TLS allows specifying some TLS configuration per listener.
|
// TLS allows specifying some TLS configuration per listener.
|
||||||
TLS *GatewayServiceTLSConfig `json:",omitempty"`
|
TLS *GatewayServiceTLSConfig `json:",omitempty"`
|
||||||
|
|
||||||
|
|
|
@ -157,8 +157,9 @@ func TestAPI_ConfigEntries_IngressGateway(t *testing.T) {
|
||||||
|
|
||||||
require.Len(t, readIngress.Listeners, 1)
|
require.Len(t, readIngress.Listeners, 1)
|
||||||
require.Len(t, readIngress.Listeners[0].Services, 1)
|
require.Len(t, readIngress.Listeners[0].Services, 1)
|
||||||
// Set namespace to blank so that OSS and ent can utilize the same tests
|
// Set namespace and partition to blank so that OSS and ent can utilize the same tests
|
||||||
readIngress.Listeners[0].Services[0].Namespace = ""
|
readIngress.Listeners[0].Services[0].Namespace = ""
|
||||||
|
readIngress.Listeners[0].Services[0].Partition = ""
|
||||||
|
|
||||||
require.Equal(t, ingress1.Listeners, readIngress.Listeners)
|
require.Equal(t, ingress1.Listeners, readIngress.Listeners)
|
||||||
case "bar":
|
case "bar":
|
||||||
|
@ -168,8 +169,9 @@ func TestAPI_ConfigEntries_IngressGateway(t *testing.T) {
|
||||||
require.Equal(t, ingress2.Name, readIngress.Name)
|
require.Equal(t, ingress2.Name, readIngress.Name)
|
||||||
require.Len(t, readIngress.Listeners, 1)
|
require.Len(t, readIngress.Listeners, 1)
|
||||||
require.Len(t, readIngress.Listeners[0].Services, 1)
|
require.Len(t, readIngress.Listeners[0].Services, 1)
|
||||||
// Set namespace to blank so that OSS and ent can utilize the same tests
|
// Set namespace and partition to blank so that OSS and ent can utilize the same tests
|
||||||
readIngress.Listeners[0].Services[0].Namespace = ""
|
readIngress.Listeners[0].Services[0].Namespace = ""
|
||||||
|
readIngress.Listeners[0].Services[0].Partition = ""
|
||||||
|
|
||||||
require.Equal(t, ingress2.Listeners, readIngress.Listeners)
|
require.Equal(t, ingress2.Listeners, readIngress.Listeners)
|
||||||
}
|
}
|
||||||
|
|
|
@ -964,7 +964,8 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
"Services": [
|
"Services": [
|
||||||
{
|
{
|
||||||
"Name": "web",
|
"Name": "web",
|
||||||
"Namespace": "foo"
|
"Namespace": "foo",
|
||||||
|
"Partition": "bar"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "db"
|
"Name": "db"
|
||||||
|
@ -1001,6 +1002,7 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
{
|
{
|
||||||
Name: "web",
|
Name: "web",
|
||||||
Namespace: "foo",
|
Namespace: "foo",
|
||||||
|
Partition: "bar",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "db",
|
Name: "db",
|
||||||
|
|
|
@ -30,6 +30,11 @@ type Intention struct {
|
||||||
SourceNS, SourceName string
|
SourceNS, SourceName string
|
||||||
DestinationNS, DestinationName string
|
DestinationNS, DestinationName string
|
||||||
|
|
||||||
|
// SourcePartition and DestinationPartition cannot be wildcards "*" and
|
||||||
|
// are not compatible with legacy intentions.
|
||||||
|
SourcePartition string
|
||||||
|
DestinationPartition string
|
||||||
|
|
||||||
// SourceType is the type of the value for the source.
|
// SourceType is the type of the value for the source.
|
||||||
SourceType IntentionSourceType
|
SourceType IntentionSourceType
|
||||||
|
|
||||||
|
@ -363,8 +368,8 @@ func (h *Connect) IntentionCheck(args *IntentionCheck, q *QueryOptions) (bool, *
|
||||||
func (c *Connect) IntentionUpsert(ixn *Intention, q *WriteOptions) (*WriteMeta, error) {
|
func (c *Connect) IntentionUpsert(ixn *Intention, q *WriteOptions) (*WriteMeta, error) {
|
||||||
r := c.c.newRequest("PUT", "/v1/connect/intentions/exact")
|
r := c.c.newRequest("PUT", "/v1/connect/intentions/exact")
|
||||||
r.setWriteOptions(q)
|
r.setWriteOptions(q)
|
||||||
r.params.Set("source", maybePrefixNamespace(ixn.SourceNS, ixn.SourceName))
|
r.params.Set("source", maybePrefixNamespaceAndPartition(ixn.SourcePartition, ixn.SourceNS, ixn.SourceName))
|
||||||
r.params.Set("destination", maybePrefixNamespace(ixn.DestinationNS, ixn.DestinationName))
|
r.params.Set("destination", maybePrefixNamespaceAndPartition(ixn.DestinationPartition, ixn.DestinationNS, ixn.DestinationName))
|
||||||
r.obj = ixn
|
r.obj = ixn
|
||||||
rtt, resp, err := c.c.doRequest(r)
|
rtt, resp, err := c.c.doRequest(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -380,11 +385,17 @@ func (c *Connect) IntentionUpsert(ixn *Intention, q *WriteOptions) (*WriteMeta,
|
||||||
return wm, nil
|
return wm, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func maybePrefixNamespace(ns, name string) string {
|
func maybePrefixNamespaceAndPartition(part, ns, name string) string {
|
||||||
if ns == "" {
|
switch {
|
||||||
|
case part == "" && ns == "":
|
||||||
return name
|
return name
|
||||||
}
|
case part == "" && ns != "":
|
||||||
return ns + "/" + name
|
return ns + "/" + name
|
||||||
|
case part != "" && ns == "":
|
||||||
|
return part + "/" + IntentionDefaultNamespace + "/" + name
|
||||||
|
default:
|
||||||
|
return part + "/" + ns + "/" + name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IntentionCreate will create a new intention. The ID in the given
|
// IntentionCreate will create a new intention. The ID in the given
|
||||||
|
|
|
@ -33,6 +33,8 @@ func TestAPI_ConnectIntentionCreateListGetUpdateDelete(t *testing.T) {
|
||||||
ixn.UpdatedAt = actual.UpdatedAt
|
ixn.UpdatedAt = actual.UpdatedAt
|
||||||
ixn.CreateIndex = actual.CreateIndex
|
ixn.CreateIndex = actual.CreateIndex
|
||||||
ixn.ModifyIndex = actual.ModifyIndex
|
ixn.ModifyIndex = actual.ModifyIndex
|
||||||
|
ixn.SourcePartition = actual.SourcePartition
|
||||||
|
ixn.DestinationPartition = actual.DestinationPartition
|
||||||
ixn.Hash = actual.Hash
|
ixn.Hash = actual.Hash
|
||||||
require.Equal(t, ixn, actual)
|
require.Equal(t, ixn, actual)
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,9 @@ type AdminPartition struct {
|
||||||
ModifyIndex uint64 `json:"ModifyIndex,omitempty"`
|
ModifyIndex uint64 `json:"ModifyIndex,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PartitionDefaultName is the default partition value.
|
||||||
|
const PartitionDefaultName = "default"
|
||||||
|
|
||||||
type AdminPartitions struct {
|
type AdminPartitions struct {
|
||||||
Partitions []*AdminPartition
|
Partitions []*AdminPartition
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mitchellh/cli"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/agent"
|
"github.com/hashicorp/consul/agent"
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
|
||||||
"github.com/hashicorp/consul/api"
|
"github.com/hashicorp/consul/api"
|
||||||
"github.com/hashicorp/consul/command/flags"
|
"github.com/hashicorp/consul/command/flags"
|
||||||
"github.com/hashicorp/consul/command/intention"
|
"github.com/hashicorp/consul/command/intention"
|
||||||
"github.com/mitchellh/cli"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(ui cli.Ui) *cmd {
|
func New(ui cli.Ui) *cmd {
|
||||||
|
@ -36,12 +36,12 @@ type cmd struct {
|
||||||
func (c *cmd) init() {
|
func (c *cmd) init() {
|
||||||
c.flags = flag.NewFlagSet("", flag.ContinueOnError)
|
c.flags = flag.NewFlagSet("", flag.ContinueOnError)
|
||||||
c.flags.StringVar(&c.ingressGateway, "ingress-gateway", "",
|
c.flags.StringVar(&c.ingressGateway, "ingress-gateway", "",
|
||||||
"(Required) The name of the ingress gateway service to use. A namespace "+
|
"(Required) The name of the ingress gateway service to use. Namespace and partition "+
|
||||||
"can optionally be specified as a prefix via the 'namespace/service' format.")
|
"can optionally be specified as a prefix via the 'partition/namespace/service' format.")
|
||||||
|
|
||||||
c.flags.StringVar(&c.service, "service", "",
|
c.flags.StringVar(&c.service, "service", "",
|
||||||
"(Required) The name of destination service to expose. A namespace "+
|
"(Required) The name of destination service to expose. Namespace and partition "+
|
||||||
"can optionally be specified as a prefix via the 'namespace/service' format.")
|
"can optionally be specified as a prefix via the 'partition/namespace/service' format.")
|
||||||
|
|
||||||
c.flags.IntVar(&c.port, "port", 0,
|
c.flags.IntVar(&c.port, "port", 0,
|
||||||
"(Required) The listener port to use for the service on the Ingress gateway.")
|
"(Required) The listener port to use for the service on the Ingress gateway.")
|
||||||
|
@ -79,7 +79,7 @@ func (c *cmd) Run(args []string) int {
|
||||||
c.UI.Error("A service name must be given via the -service flag.")
|
c.UI.Error("A service name must be given via the -service flag.")
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
svc, svcNamespace, err := intention.ParseIntentionTarget(c.service)
|
svc, svcNS, svcPart, err := intention.ParseIntentionTarget(c.service)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.UI.Error(fmt.Sprintf("Invalid service name: %s", err))
|
c.UI.Error(fmt.Sprintf("Invalid service name: %s", err))
|
||||||
return 1
|
return 1
|
||||||
|
@ -89,7 +89,7 @@ func (c *cmd) Run(args []string) int {
|
||||||
c.UI.Error("An ingress gateway service must be given via the -ingress-gateway flag.")
|
c.UI.Error("An ingress gateway service must be given via the -ingress-gateway flag.")
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
gateway, gatewayNamespace, err := intention.ParseIntentionTarget(c.ingressGateway)
|
gateway, gatewayNS, gatewayPart, err := intention.ParseIntentionTarget(c.ingressGateway)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.UI.Error(fmt.Sprintf("Invalid ingress gateway name: %s", err))
|
c.UI.Error(fmt.Sprintf("Invalid ingress gateway name: %s", err))
|
||||||
return 1
|
return 1
|
||||||
|
@ -102,7 +102,9 @@ func (c *cmd) Run(args []string) int {
|
||||||
|
|
||||||
// First get the config entry for the ingress gateway, if it exists. Don't error if it's a 404 as that
|
// First get the config entry for the ingress gateway, if it exists. Don't error if it's a 404 as that
|
||||||
// just means we'll need to create a new config entry.
|
// just means we'll need to create a new config entry.
|
||||||
conf, _, err := client.ConfigEntries().Get(api.IngressGateway, gateway, nil)
|
conf, _, err := client.ConfigEntries().Get(
|
||||||
|
api.IngressGateway, gateway, &api.QueryOptions{Partition: gatewayPart, Namespace: gatewayNS},
|
||||||
|
)
|
||||||
if err != nil && !strings.Contains(err.Error(), agent.ConfigEntryNotFoundErr) {
|
if err != nil && !strings.Contains(err.Error(), agent.ConfigEntryNotFoundErr) {
|
||||||
c.UI.Error(fmt.Sprintf("Error fetching existing ingress gateway configuration: %s", err))
|
c.UI.Error(fmt.Sprintf("Error fetching existing ingress gateway configuration: %s", err))
|
||||||
return 1
|
return 1
|
||||||
|
@ -111,7 +113,8 @@ func (c *cmd) Run(args []string) int {
|
||||||
conf = &api.IngressGatewayConfigEntry{
|
conf = &api.IngressGatewayConfigEntry{
|
||||||
Kind: api.IngressGateway,
|
Kind: api.IngressGateway,
|
||||||
Name: gateway,
|
Name: gateway,
|
||||||
Namespace: gatewayNamespace,
|
Namespace: gatewayNS,
|
||||||
|
Partition: gatewayPart,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +130,8 @@ func (c *cmd) Run(args []string) int {
|
||||||
serviceIdx := -1
|
serviceIdx := -1
|
||||||
newService := api.IngressService{
|
newService := api.IngressService{
|
||||||
Name: svc,
|
Name: svc,
|
||||||
Namespace: svcNamespace,
|
Namespace: svcNS,
|
||||||
|
Partition: svcPart,
|
||||||
Hosts: c.hosts,
|
Hosts: c.hosts,
|
||||||
}
|
}
|
||||||
for i, listener := range ingressConf.Listeners {
|
for i, listener := range ingressConf.Listeners {
|
||||||
|
@ -145,7 +149,7 @@ func (c *cmd) Run(args []string) int {
|
||||||
|
|
||||||
// Make sure the service isn't already exposed in this gateway
|
// Make sure the service isn't already exposed in this gateway
|
||||||
for j, service := range listener.Services {
|
for j, service := range listener.Services {
|
||||||
if service.Name == svc && namespaceMatch(service.Namespace, svcNamespace) {
|
if service.Name == svc && entMetaMatch(service.Namespace, service.Partition, svcNS, svcPart) {
|
||||||
serviceIdx = j
|
serviceIdx = j
|
||||||
c.UI.Output(fmt.Sprintf("Updating service definition for %q on listener with port %d", c.service, listener.Port))
|
c.UI.Output(fmt.Sprintf("Updating service definition for %q on listener with port %d", c.service, listener.Port))
|
||||||
break
|
break
|
||||||
|
@ -170,7 +174,7 @@ func (c *cmd) Run(args []string) int {
|
||||||
|
|
||||||
// Write the updated config entry using a check-and-set, so it fails if the entry
|
// Write the updated config entry using a check-and-set, so it fails if the entry
|
||||||
// has been changed since we looked it up.
|
// has been changed since we looked it up.
|
||||||
succeeded, _, err := client.ConfigEntries().CAS(ingressConf, ingressConf.GetModifyIndex(), nil)
|
succeeded, _, err := client.ConfigEntries().CAS(ingressConf, ingressConf.GetModifyIndex(), &api.WriteOptions{Partition: gatewayPart, Namespace: gatewayNS})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.UI.Error(fmt.Sprintf("Error writing ingress config entry: %v", err))
|
c.UI.Error(fmt.Sprintf("Error writing ingress config entry: %v", err))
|
||||||
return 1
|
return 1
|
||||||
|
@ -195,9 +199,11 @@ func (c *cmd) Run(args []string) int {
|
||||||
// Add the intention between the gateway service and the destination.
|
// Add the intention between the gateway service and the destination.
|
||||||
ixn := &api.Intention{
|
ixn := &api.Intention{
|
||||||
SourceName: gateway,
|
SourceName: gateway,
|
||||||
SourceNS: gatewayNamespace,
|
SourceNS: gatewayNS,
|
||||||
|
SourcePartition: gatewayPart,
|
||||||
DestinationName: svc,
|
DestinationName: svc,
|
||||||
DestinationNS: svcNamespace,
|
DestinationNS: svcNS,
|
||||||
|
DestinationPartition: svcPart,
|
||||||
SourceType: api.IntentionSourceConsul,
|
SourceType: api.IntentionSourceConsul,
|
||||||
Action: api.IntentionActionAllow,
|
Action: api.IntentionActionAllow,
|
||||||
}
|
}
|
||||||
|
@ -210,17 +216,21 @@ func (c *cmd) Run(args []string) int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func namespaceMatch(a, b string) bool {
|
func entMetaMatch(nsA, partitionA, nsB, partitionB string) bool {
|
||||||
namespaceA := a
|
if nsA == "" {
|
||||||
namespaceB := b
|
nsA = api.IntentionDefaultNamespace
|
||||||
if namespaceA == "" {
|
|
||||||
namespaceA = structs.IntentionDefaultNamespace
|
|
||||||
}
|
}
|
||||||
if namespaceB == "" {
|
if partitionA == "" {
|
||||||
namespaceB = structs.IntentionDefaultNamespace
|
partitionA = api.PartitionDefaultName
|
||||||
|
}
|
||||||
|
if nsB == "" {
|
||||||
|
nsB = api.IntentionDefaultNamespace
|
||||||
|
}
|
||||||
|
if partitionB == "" {
|
||||||
|
partitionB = api.PartitionDefaultName
|
||||||
}
|
}
|
||||||
|
|
||||||
return namespaceA == namespaceB
|
return strings.EqualFold(partitionA, partitionB) && strings.EqualFold(nsA, nsB)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cmd) Synopsis() string {
|
func (c *cmd) Synopsis() string {
|
||||||
|
|
|
@ -43,6 +43,7 @@ func TestConnectExpose(t *testing.T) {
|
||||||
entry, _, err := client.ConfigEntries().Get(api.IngressGateway, "ingress", nil)
|
entry, _, err := client.ConfigEntries().Get(api.IngressGateway, "ingress", nil)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
ns := entry.(*api.IngressGatewayConfigEntry).Namespace
|
ns := entry.(*api.IngressGatewayConfigEntry).Namespace
|
||||||
|
ap := entry.(*api.IngressGatewayConfigEntry).Partition
|
||||||
expected := &api.IngressGatewayConfigEntry{
|
expected := &api.IngressGatewayConfigEntry{
|
||||||
Kind: api.IngressGateway,
|
Kind: api.IngressGateway,
|
||||||
Name: "ingress",
|
Name: "ingress",
|
||||||
|
@ -55,6 +56,7 @@ func TestConnectExpose(t *testing.T) {
|
||||||
{
|
{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Namespace: ns,
|
Namespace: ns,
|
||||||
|
Partition: ap,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -95,6 +97,7 @@ func TestConnectExpose(t *testing.T) {
|
||||||
{
|
{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Namespace: ns,
|
Namespace: ns,
|
||||||
|
Partition: ap,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -283,6 +286,7 @@ func TestConnectExpose_existingConfig(t *testing.T) {
|
||||||
ingressConf.Namespace = entryConf.Namespace
|
ingressConf.Namespace = entryConf.Namespace
|
||||||
for i, listener := range ingressConf.Listeners {
|
for i, listener := range ingressConf.Listeners {
|
||||||
listener.Services[0].Namespace = entryConf.Listeners[i].Services[0].Namespace
|
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.CreateIndex = entry.GetCreateIndex()
|
||||||
ingressConf.ModifyIndex = entry.GetModifyIndex()
|
ingressConf.ModifyIndex = entry.GetModifyIndex()
|
||||||
|
@ -317,6 +321,7 @@ func TestConnectExpose_existingConfig(t *testing.T) {
|
||||||
ingressConf.Listeners[1].Services = append(ingressConf.Listeners[1].Services, api.IngressService{
|
ingressConf.Listeners[1].Services = append(ingressConf.Listeners[1].Services, api.IngressService{
|
||||||
Name: "zoo",
|
Name: "zoo",
|
||||||
Namespace: entryConf.Listeners[1].Services[1].Namespace,
|
Namespace: entryConf.Listeners[1].Services[1].Namespace,
|
||||||
|
Partition: entryConf.Listeners[1].Services[1].Partition,
|
||||||
Hosts: []string{"foo.com", "foo.net"},
|
Hosts: []string{"foo.com", "foo.net"},
|
||||||
})
|
})
|
||||||
ingressConf.CreateIndex = entry.GetCreateIndex()
|
ingressConf.CreateIndex = entry.GetCreateIndex()
|
||||||
|
|
|
@ -153,20 +153,22 @@ func (c *cmd) ixnsFromArgs(args []string) ([]*api.Intention, error) {
|
||||||
return nil, fmt.Errorf("Must specify two arguments: source and destination")
|
return nil, fmt.Errorf("Must specify two arguments: source and destination")
|
||||||
}
|
}
|
||||||
|
|
||||||
srcName, srcNamespace, err := intention.ParseIntentionTarget(args[0])
|
srcName, srcNS, srcPart, err := intention.ParseIntentionTarget(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Invalid intention source: %v", err)
|
return nil, fmt.Errorf("Invalid intention source: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dstName, dstNamespace, err := intention.ParseIntentionTarget(args[1])
|
dstName, dstNS, dstPart, err := intention.ParseIntentionTarget(args[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Invalid intention destination: %v", err)
|
return nil, fmt.Errorf("Invalid intention destination: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return []*api.Intention{{
|
return []*api.Intention{{
|
||||||
SourceNS: srcNamespace,
|
SourcePartition: srcPart,
|
||||||
|
SourceNS: srcNS,
|
||||||
SourceName: srcName,
|
SourceName: srcName,
|
||||||
DestinationNS: dstNamespace,
|
DestinationPartition: dstPart,
|
||||||
|
DestinationNS: dstNS,
|
||||||
DestinationName: dstName,
|
DestinationName: dstName,
|
||||||
SourceType: api.IntentionSourceConsul,
|
SourceType: api.IntentionSourceConsul,
|
||||||
Action: c.ixnAction(),
|
Action: c.ixnAction(),
|
||||||
|
|
|
@ -7,25 +7,28 @@ import (
|
||||||
"github.com/hashicorp/consul/api"
|
"github.com/hashicorp/consul/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ParseIntentionTarget parses a target of the form <namespace>/<name> and returns
|
// ParseIntentionTarget parses a target of the form <partition>/<namespace>/<name> and returns
|
||||||
// the two distinct parts. In some cases the namespace may be elided and this function
|
// the distinct parts. In some cases the partition and namespace may be elided and this function
|
||||||
// will return the empty string for the namespace then.
|
// will return the empty string for them then.
|
||||||
func ParseIntentionTarget(input string) (name string, namespace string, err error) {
|
// If two parts are present, it is assumed they are namespace/name and not partition/name.
|
||||||
// Get the index to the '/'. If it doesn't exist, we have just a name
|
func ParseIntentionTarget(input string) (name string, ns string, partition string, err error) {
|
||||||
// so just set that and return.
|
ss := strings.Split(input, "/")
|
||||||
idx := strings.IndexByte(input, '/')
|
switch len(ss) {
|
||||||
if idx == -1 {
|
case 1: // Name only
|
||||||
// let the agent do token based defaulting of the namespace
|
name = ss[0]
|
||||||
return input, "", nil
|
return
|
||||||
|
case 2: // namespace/name
|
||||||
|
ns = ss[0]
|
||||||
|
name = ss[1]
|
||||||
|
return
|
||||||
|
case 3: // partition/namespace/name
|
||||||
|
partition = ss[0]
|
||||||
|
ns = ss[1]
|
||||||
|
name = ss[2]
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
return "", "", "", fmt.Errorf("input can contain at most two '/'")
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace = input[:idx]
|
|
||||||
name = input[idx+1:]
|
|
||||||
if strings.IndexByte(name, '/') != -1 {
|
|
||||||
return "", "", fmt.Errorf("target can contain at most one '/'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return name, namespace, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetFromArgs(client *api.Client, args []string) (*api.Intention, error) {
|
func GetFromArgs(client *api.Client, args []string) (*api.Intention, error) {
|
||||||
|
|
|
@ -3,3 +3,4 @@
|
||||||
export DEFAULT_REQUIRED_SERVICES="s1 s1-sidecar-proxy s2 s2-sidecar-proxy"
|
export DEFAULT_REQUIRED_SERVICES="s1 s1-sidecar-proxy s2 s2-sidecar-proxy"
|
||||||
export REQUIRED_SERVICES="${DEFAULT_REQUIRED_SERVICES}"
|
export REQUIRED_SERVICES="${DEFAULT_REQUIRED_SERVICES}"
|
||||||
export REQUIRE_SECONDARY=0
|
export REQUIRE_SECONDARY=0
|
||||||
|
export REQUIRE_PARTITIONS=0
|
|
@ -115,14 +115,19 @@ function assert_proxy_presents_cert_uri {
|
||||||
local SERVICENAME=$2
|
local SERVICENAME=$2
|
||||||
local DC=${3:-primary}
|
local DC=${3:-primary}
|
||||||
local NS=${4:-default}
|
local NS=${4:-default}
|
||||||
|
local PARTITION=${5:default}
|
||||||
|
|
||||||
CERT=$(retry_default get_cert $HOSTPORT)
|
CERT=$(retry_default get_cert $HOSTPORT)
|
||||||
|
|
||||||
echo "WANT SERVICE: ${NS}/${SERVICENAME}"
|
echo "WANT SERVICE: ${PARTITION}/${NS}/${SERVICENAME}"
|
||||||
echo "GOT CERT:"
|
echo "GOT CERT:"
|
||||||
echo "$CERT"
|
echo "$CERT"
|
||||||
|
|
||||||
|
if [[ -z $PARTITION ]] || [[ $PARTITION = "default" ]]; then
|
||||||
echo "$CERT" | grep -Eo "URI:spiffe://([a-zA-Z0-9-]+).consul/ns/${NS}/dc/${DC}/svc/$SERVICENAME"
|
echo "$CERT" | grep -Eo "URI:spiffe://([a-zA-Z0-9-]+).consul/ns/${NS}/dc/${DC}/svc/$SERVICENAME"
|
||||||
|
else
|
||||||
|
echo "$CERT" | grep -Eo "URI:spiffe://([a-zA-Z0-9-]+).consul/ap/${PARTITION}/ns/${NS}/dc/${DC}/svc/$SERVICENAME"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function assert_dnssan_in_cert {
|
function assert_dnssan_in_cert {
|
||||||
|
|
|
@ -40,39 +40,39 @@ function network_snippet {
|
||||||
}
|
}
|
||||||
|
|
||||||
function init_workdir {
|
function init_workdir {
|
||||||
local DC="$1"
|
local CLUSTER="$1"
|
||||||
|
|
||||||
if test -z "$DC"
|
if test -z "$CLUSTER"
|
||||||
then
|
then
|
||||||
DC=primary
|
CLUSTER=primary
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Note, we use explicit set of dirs so we don't delete .gitignore. Also,
|
# Note, we use explicit set of dirs so we don't delete .gitignore. Also,
|
||||||
# don't wipe logs between runs as they are already split and we need them to
|
# don't wipe logs between runs as they are already split and we need them to
|
||||||
# upload as artifacts later.
|
# upload as artifacts later.
|
||||||
rm -rf workdir/${DC}
|
rm -rf workdir/${CLUSTER}
|
||||||
mkdir -p workdir/${DC}/{consul,register,envoy,bats,statsd,data}
|
mkdir -p workdir/${CLUSTER}/{consul,register,envoy,bats,statsd,data}
|
||||||
|
|
||||||
# Reload consul config from defaults
|
# Reload consul config from defaults
|
||||||
cp consul-base-cfg/*.hcl workdir/${DC}/consul/
|
cp consul-base-cfg/*.hcl workdir/${CLUSTER}/consul/
|
||||||
|
|
||||||
# Add any overrides if there are any (no op if not)
|
# Add any overrides if there are any (no op if not)
|
||||||
find ${CASE_DIR} -maxdepth 1 -name '*.hcl' -type f -exec cp -f {} workdir/${DC}/consul \;
|
find ${CASE_DIR} -maxdepth 1 -name '*.hcl' -type f -exec cp -f {} workdir/${CLUSTER}/consul \;
|
||||||
|
|
||||||
# Copy all the test files
|
# Copy all the test files
|
||||||
find ${CASE_DIR} -maxdepth 1 -name '*.bats' -type f -exec cp -f {} workdir/${DC}/bats \;
|
find ${CASE_DIR} -maxdepth 1 -name '*.bats' -type f -exec cp -f {} workdir/${CLUSTER}/bats \;
|
||||||
# Copy DC specific bats
|
# Copy CLUSTER specific bats
|
||||||
cp helpers.bash workdir/${DC}/bats
|
cp helpers.bash workdir/${CLUSTER}/bats
|
||||||
|
|
||||||
# Add any DC overrides
|
# Add any CLUSTER overrides
|
||||||
if test -d "${CASE_DIR}/${DC}"
|
if test -d "${CASE_DIR}/${CLUSTER}"
|
||||||
then
|
then
|
||||||
find ${CASE_DIR}/${DC} -type f -name '*.hcl' -exec cp -f {} workdir/${DC}/consul \;
|
find ${CASE_DIR}/${CLUSTER} -type f -name '*.hcl' -exec cp -f {} workdir/${CLUSTER}/consul \;
|
||||||
find ${CASE_DIR}/${DC} -type f -name '*.bats' -exec cp -f {} workdir/${DC}/bats \;
|
find ${CASE_DIR}/${CLUSTER} -type f -name '*.bats' -exec cp -f {} workdir/${CLUSTER}/bats \;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# move all of the registration files OUT of the consul config dir now
|
# move all of the registration files OUT of the consul config dir now
|
||||||
find workdir/${DC}/consul -type f -name 'service_*.hcl' -exec mv -f {} workdir/${DC}/register \;
|
find workdir/${CLUSTER}/consul -type f -name 'service_*.hcl' -exec mv -f {} workdir/${CLUSTER}/register \;
|
||||||
|
|
||||||
# copy the ca-certs for SDS so we can verify the right ones are served
|
# copy the ca-certs for SDS so we can verify the right ones are served
|
||||||
mkdir -p workdir/test-sds-server/certs
|
mkdir -p workdir/test-sds-server/certs
|
||||||
|
@ -80,7 +80,7 @@ function init_workdir {
|
||||||
|
|
||||||
if test -d "${CASE_DIR}/data"
|
if test -d "${CASE_DIR}/data"
|
||||||
then
|
then
|
||||||
cp -r ${CASE_DIR}/data/* workdir/${DC}/data
|
cp -r ${CASE_DIR}/data/* workdir/${CLUSTER}/data
|
||||||
fi
|
fi
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
@ -157,13 +157,48 @@ function start_consul {
|
||||||
-client "0.0.0.0" >/dev/null
|
-client "0.0.0.0" >/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function start_partitioned_client {
|
||||||
|
local PARTITION=${1:-ap1}
|
||||||
|
|
||||||
|
# Start consul now as setup script needs it up
|
||||||
|
docker_kill_rm consul-${PARTITION}
|
||||||
|
|
||||||
|
license="${CONSUL_LICENSE:-}"
|
||||||
|
# load the consul license so we can pass it into the consul
|
||||||
|
# containers as an env var in the case that this is a consul
|
||||||
|
# enterprise test
|
||||||
|
if test -z "$license" -a -n "${CONSUL_LICENSE_PATH:-}"
|
||||||
|
then
|
||||||
|
license=$(cat $CONSUL_LICENSE_PATH)
|
||||||
|
fi
|
||||||
|
|
||||||
|
sh -c "rm -rf /workdir/${PARTITION}/data"
|
||||||
|
|
||||||
|
# Run consul and expose some ports to the host to make debugging locally a
|
||||||
|
# bit easier.
|
||||||
|
#
|
||||||
|
docker run -d --name envoy_consul-${PARTITION}_1 \
|
||||||
|
--net=envoy-tests \
|
||||||
|
$WORKDIR_SNIPPET \
|
||||||
|
--hostname "consul-${PARTITION}" \
|
||||||
|
--network-alias "consul-${PARTITION}" \
|
||||||
|
-e "CONSUL_LICENSE=$license" \
|
||||||
|
consul-dev agent \
|
||||||
|
-datacenter "primary" \
|
||||||
|
-retry-join "consul-primary" \
|
||||||
|
-grpc-port 8502 \
|
||||||
|
-data-dir "/tmp/consul" \
|
||||||
|
-config-dir "/workdir/${PARTITION}/consul" \
|
||||||
|
-client "0.0.0.0" >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
function pre_service_setup {
|
function pre_service_setup {
|
||||||
local DC=${1:-primary}
|
local CLUSTER=${1:-primary}
|
||||||
|
|
||||||
# Run test case setup (e.g. generating Envoy bootstrap, starting containers)
|
# Run test case setup (e.g. generating Envoy bootstrap, starting containers)
|
||||||
if [ -f "${CASE_DIR}/${DC}/setup.sh" ]
|
if [ -f "${CASE_DIR}/${CLUSTER}/setup.sh" ]
|
||||||
then
|
then
|
||||||
source ${CASE_DIR}/${DC}/setup.sh
|
source ${CASE_DIR}/${CLUSTER}/setup.sh
|
||||||
else
|
else
|
||||||
source ${CASE_DIR}/setup.sh
|
source ${CASE_DIR}/setup.sh
|
||||||
fi
|
fi
|
||||||
|
@ -184,29 +219,29 @@ function start_services {
|
||||||
}
|
}
|
||||||
|
|
||||||
function verify {
|
function verify {
|
||||||
local DC=$1
|
local CLUSTER="$1"
|
||||||
if test -z "$DC"; then
|
if test -z "$CLUSTER"; then
|
||||||
DC=primary
|
CLUSTER="primary"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Execute tests
|
# Execute tests
|
||||||
res=0
|
res=0
|
||||||
|
|
||||||
# Nuke any previous case's verify container.
|
# Nuke any previous case's verify container.
|
||||||
docker_kill_rm verify-${DC}
|
docker_kill_rm verify-${CLUSTER}
|
||||||
|
|
||||||
echo "Running ${DC} verification step for ${CASE_DIR}..."
|
echo "Running ${CLUSTER} verification step for ${CASE_DIR}..."
|
||||||
|
|
||||||
# need to tell the PID 1 inside of the container that it won't be actual PID
|
# need to tell the PID 1 inside of the container that it won't be actual PID
|
||||||
# 1 because we're using --pid=host so we use TINI_SUBREAPER
|
# 1 because we're using --pid=host so we use TINI_SUBREAPER
|
||||||
if docker run --name envoy_verify-${DC}_1 -t \
|
if docker run --name envoy_verify-${CLUSTER}_1 -t \
|
||||||
-e TINI_SUBREAPER=1 \
|
-e TINI_SUBREAPER=1 \
|
||||||
-e ENVOY_VERSION \
|
-e ENVOY_VERSION \
|
||||||
$WORKDIR_SNIPPET \
|
$WORKDIR_SNIPPET \
|
||||||
--pid=host \
|
--pid=host \
|
||||||
$(network_snippet $DC) \
|
$(network_snippet $CLUSTER) \
|
||||||
bats-verify \
|
bats-verify \
|
||||||
--pretty /workdir/${DC}/bats ; then
|
--pretty /workdir/${CLUSTER}/bats ; then
|
||||||
echogreen "✓ PASS"
|
echogreen "✓ PASS"
|
||||||
else
|
else
|
||||||
echored "⨯ FAIL"
|
echored "⨯ FAIL"
|
||||||
|
@ -228,6 +263,11 @@ function capture_logs {
|
||||||
then
|
then
|
||||||
services="$services consul-secondary"
|
services="$services consul-secondary"
|
||||||
fi
|
fi
|
||||||
|
if is_set $REQUIRE_PARTITIONS
|
||||||
|
then
|
||||||
|
services="$services consul-ap1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [ -f "${CASE_DIR}/capture.sh" ]
|
if [ -f "${CASE_DIR}/capture.sh" ]
|
||||||
then
|
then
|
||||||
|
@ -247,7 +287,7 @@ function stop_services {
|
||||||
# Teardown
|
# Teardown
|
||||||
docker_kill_rm $REQUIRED_SERVICES
|
docker_kill_rm $REQUIRED_SERVICES
|
||||||
|
|
||||||
docker_kill_rm consul-primary consul-secondary
|
docker_kill_rm consul-primary consul-secondary consul-ap1
|
||||||
}
|
}
|
||||||
|
|
||||||
function init_vars {
|
function init_vars {
|
||||||
|
@ -286,6 +326,10 @@ function run_tests {
|
||||||
then
|
then
|
||||||
init_workdir secondary
|
init_workdir secondary
|
||||||
fi
|
fi
|
||||||
|
if is_set $REQUIRE_PARTITIONS
|
||||||
|
then
|
||||||
|
init_workdir ap1
|
||||||
|
fi
|
||||||
|
|
||||||
global_setup
|
global_setup
|
||||||
|
|
||||||
|
@ -307,6 +351,10 @@ function run_tests {
|
||||||
if is_set $REQUIRE_SECONDARY; then
|
if is_set $REQUIRE_SECONDARY; then
|
||||||
start_consul secondary
|
start_consul secondary
|
||||||
fi
|
fi
|
||||||
|
if is_set $REQUIRE_PARTITIONS; then
|
||||||
|
docker_consul "primary" admin-partition create -name ap1 > /dev/null
|
||||||
|
start_partitioned_client ap1
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Setting up the primary datacenter"
|
echo "Setting up the primary datacenter"
|
||||||
pre_service_setup primary
|
pre_service_setup primary
|
||||||
|
@ -315,14 +363,20 @@ function run_tests {
|
||||||
echo "Setting up the secondary datacenter"
|
echo "Setting up the secondary datacenter"
|
||||||
pre_service_setup secondary
|
pre_service_setup secondary
|
||||||
fi
|
fi
|
||||||
|
if is_set $REQUIRE_PARTITIONS; then
|
||||||
|
echo "Setting up the non-default partition"
|
||||||
|
pre_service_setup ap1
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Starting services"
|
echo "Starting services"
|
||||||
start_services
|
start_services
|
||||||
|
|
||||||
# Run the verify container and report on the output
|
# Run the verify container and report on the output
|
||||||
|
echo "Verifying the primary datacenter"
|
||||||
verify primary
|
verify primary
|
||||||
|
|
||||||
if is_set $REQUIRE_SECONDARY; then
|
if is_set $REQUIRE_SECONDARY; then
|
||||||
|
echo "Verifying the secondary datacenter"
|
||||||
verify secondary
|
verify secondary
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -378,7 +432,7 @@ function suite_teardown {
|
||||||
docker_kill_rm $(grep "^function run_container_" $self_name | \
|
docker_kill_rm $(grep "^function run_container_" $self_name | \
|
||||||
sed 's/^function run_container_\(.*\) {/\1/g')
|
sed 's/^function run_container_\(.*\) {/\1/g')
|
||||||
|
|
||||||
docker_kill_rm consul-primary consul-secondary
|
docker_kill_rm consul-primary consul-secondary consul-ap1
|
||||||
|
|
||||||
if docker network inspect envoy-tests &>/dev/null ; then
|
if docker network inspect envoy-tests &>/dev/null ; then
|
||||||
echo -n "Deleting network 'envoy-tests'..."
|
echo -n "Deleting network 'envoy-tests'..."
|
||||||
|
@ -402,13 +456,13 @@ function run_container {
|
||||||
|
|
||||||
function common_run_container_service {
|
function common_run_container_service {
|
||||||
local service="$1"
|
local service="$1"
|
||||||
local DC="$2"
|
local CLUSTER="$2"
|
||||||
local httpPort="$3"
|
local httpPort="$3"
|
||||||
local grpcPort="$4"
|
local grpcPort="$4"
|
||||||
|
|
||||||
docker run -d --name $(container_name_prev) \
|
docker run -d --name $(container_name_prev) \
|
||||||
-e "FORTIO_NAME=${service}" \
|
-e "FORTIO_NAME=${service}" \
|
||||||
$(network_snippet $DC) \
|
$(network_snippet $CLUSTER) \
|
||||||
"${HASHICORP_DOCKER_PROXY}/fortio/fortio" \
|
"${HASHICORP_DOCKER_PROXY}/fortio/fortio" \
|
||||||
server \
|
server \
|
||||||
-http-port ":$httpPort" \
|
-http-port ":$httpPort" \
|
||||||
|
@ -420,6 +474,10 @@ function run_container_s1 {
|
||||||
common_run_container_service s1 primary 8080 8079
|
common_run_container_service s1 primary 8080 8079
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function run_container_s1-ap1 {
|
||||||
|
common_run_container_service s1 ap1 8080 8079
|
||||||
|
}
|
||||||
|
|
||||||
function run_container_s2 {
|
function run_container_s2 {
|
||||||
common_run_container_service s2 primary 8181 8179
|
common_run_container_service s2 primary 8181 8179
|
||||||
}
|
}
|
||||||
|
@ -457,7 +515,7 @@ function run_container_s2-secondary {
|
||||||
|
|
||||||
function common_run_container_sidecar_proxy {
|
function common_run_container_sidecar_proxy {
|
||||||
local service="$1"
|
local service="$1"
|
||||||
local DC="$2"
|
local CLUSTER="$2"
|
||||||
|
|
||||||
# Hot restart breaks since both envoys seem to interact with each other
|
# Hot restart breaks since both envoys seem to interact with each other
|
||||||
# despite separate containers that don't share IPC namespace. Not quite
|
# despite separate containers that don't share IPC namespace. Not quite
|
||||||
|
@ -465,10 +523,10 @@ function common_run_container_sidecar_proxy {
|
||||||
# location?
|
# location?
|
||||||
docker run -d --name $(container_name_prev) \
|
docker run -d --name $(container_name_prev) \
|
||||||
$WORKDIR_SNIPPET \
|
$WORKDIR_SNIPPET \
|
||||||
$(network_snippet $DC) \
|
$(network_snippet $CLUSTER) \
|
||||||
"${HASHICORP_DOCKER_PROXY}/envoyproxy/envoy:v${ENVOY_VERSION}" \
|
"${HASHICORP_DOCKER_PROXY}/envoyproxy/envoy:v${ENVOY_VERSION}" \
|
||||||
envoy \
|
envoy \
|
||||||
-c /workdir/${DC}/envoy/${service}-bootstrap.json \
|
-c /workdir/${CLUSTER}/envoy/${service}-bootstrap.json \
|
||||||
-l debug \
|
-l debug \
|
||||||
--disable-hot-restart \
|
--disable-hot-restart \
|
||||||
--drain-time-s 1 >/dev/null
|
--drain-time-s 1 >/dev/null
|
||||||
|
@ -477,6 +535,11 @@ function common_run_container_sidecar_proxy {
|
||||||
function run_container_s1-sidecar-proxy {
|
function run_container_s1-sidecar-proxy {
|
||||||
common_run_container_sidecar_proxy s1 primary
|
common_run_container_sidecar_proxy s1 primary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function run_container_s1-ap1-sidecar-proxy {
|
||||||
|
common_run_container_sidecar_proxy s1 ap1
|
||||||
|
}
|
||||||
|
|
||||||
function run_container_s1-sidecar-proxy-consul-exec {
|
function run_container_s1-sidecar-proxy-consul-exec {
|
||||||
docker run -d --name $(container_name) \
|
docker run -d --name $(container_name) \
|
||||||
$(network_snippet primary) \
|
$(network_snippet primary) \
|
||||||
|
|
Loading…
Reference in New Issue