mirror of https://github.com/hashicorp/consul
144 lines
3.8 KiB
Go
144 lines
3.8 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/docker/go-connections/nat"
|
|
"github.com/hashicorp/consul/api"
|
|
"github.com/testcontainers/testcontainers-go"
|
|
"github.com/testcontainers/testcontainers-go/wait"
|
|
|
|
libnode "github.com/hashicorp/consul/test/integration/consul-container/libs/agent"
|
|
"github.com/hashicorp/consul/test/integration/consul-container/libs/utils"
|
|
)
|
|
|
|
// exampleContainer
|
|
type exampleContainer struct {
|
|
ctx context.Context
|
|
container testcontainers.Container
|
|
ip string
|
|
httpPort int
|
|
grpcPort int
|
|
serviceName string
|
|
}
|
|
|
|
func (g exampleContainer) GetName() string {
|
|
name, err := g.container.Name(g.ctx)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return name
|
|
}
|
|
|
|
func (g exampleContainer) GetAddr() (string, int) {
|
|
return g.ip, g.httpPort
|
|
}
|
|
|
|
func (g exampleContainer) Start() error {
|
|
if g.container == nil {
|
|
return fmt.Errorf("container has not been initialized")
|
|
}
|
|
return g.container.Start(context.Background())
|
|
}
|
|
|
|
// Terminate attempts to terminate the container. On failure, an error will be
|
|
// returned and the reaper process (RYUK) will handle cleanup.
|
|
func (c exampleContainer) Terminate() error {
|
|
if c.container == nil {
|
|
return nil
|
|
}
|
|
|
|
var err error
|
|
if *utils.FollowLog {
|
|
err = c.container.StopLogProducer()
|
|
if err1 := c.container.Terminate(c.ctx); err1 == nil {
|
|
err = err1
|
|
}
|
|
} else {
|
|
err = c.container.Terminate(c.ctx)
|
|
}
|
|
|
|
c.container = nil
|
|
|
|
return err
|
|
}
|
|
|
|
func (g exampleContainer) Export(partition, peerName string, client *api.Client) error {
|
|
config := &api.ExportedServicesConfigEntry{
|
|
Name: partition,
|
|
Services: []api.ExportedService{
|
|
{
|
|
Name: g.GetServiceName(),
|
|
Consumers: []api.ServiceConsumer{
|
|
// TODO: need to handle the changed field name in 1.13
|
|
{Peer: peerName},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
_, _, err := client.ConfigEntries().Set(config, &api.WriteOptions{})
|
|
return err
|
|
}
|
|
|
|
func (g exampleContainer) GetServiceName() string {
|
|
return g.serviceName
|
|
}
|
|
|
|
func NewExampleService(ctx context.Context, name string, httpPort int, grpcPort int, node libnode.Agent) (Service, error) {
|
|
namePrefix := fmt.Sprintf("%s-service-example-%s", node.GetDatacenter(), name)
|
|
containerName := utils.RandName(namePrefix)
|
|
|
|
req := testcontainers.ContainerRequest{
|
|
Image: hashicorpDockerProxy + "/fortio/fortio",
|
|
WaitingFor: wait.ForLog("").WithStartupTimeout(10 * time.Second),
|
|
AutoRemove: false,
|
|
Name: containerName,
|
|
Cmd: []string{"server", "-http-port", fmt.Sprintf("%d", httpPort), "-grpc-port", fmt.Sprintf("%d", grpcPort), "-redirect-port", "-disabled"},
|
|
Env: map[string]string{"FORTIO_NAME": name},
|
|
ExposedPorts: []string{
|
|
fmt.Sprintf("%d/tcp", httpPort), // HTTP Listener
|
|
fmt.Sprintf("%d/tcp", grpcPort), // GRPC Listener
|
|
},
|
|
}
|
|
container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
|
|
ContainerRequest: req,
|
|
Started: true,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ip, err := container.ContainerIP(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
mappedHTPPPort, err := container.MappedPort(ctx, nat.Port(fmt.Sprintf("%d", httpPort)))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
mappedGRPCPort, err := container.MappedPort(ctx, nat.Port(fmt.Sprintf("%d", grpcPort)))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if *utils.FollowLog {
|
|
if err := container.StartLogProducer(ctx); err != nil {
|
|
return nil, err
|
|
}
|
|
container.FollowOutput(&LogConsumer{
|
|
Prefix: containerName,
|
|
})
|
|
}
|
|
|
|
terminate := func() error {
|
|
return container.Terminate(context.Background())
|
|
}
|
|
node.RegisterTermination(terminate)
|
|
|
|
fmt.Printf("Example service exposed http port %d, gRPC port %d\n", mappedHTPPPort.Int(), mappedGRPCPort.Int())
|
|
return &exampleContainer{container: container, ip: ip, httpPort: mappedHTPPPort.Int(), grpcPort: mappedGRPCPort.Int(), serviceName: name}, nil
|
|
}
|