From 6b896faef7a3a0fb7020af3e38304a7b371abf3c Mon Sep 17 00:00:00 2001 From: Clement Erena Date: Wed, 16 Jul 2025 13:05:23 +0200 Subject: [PATCH 1/8] feat(local): add billing platform service --- .../billing_platform_service.go | 248 ++++++++++++++++++ .../docker-compose.yml | 74 ++++++ 2 files changed, 322 insertions(+) create mode 100644 framework/components/dockercompose/billing_platform_service/billing_platform_service.go create mode 100644 framework/components/dockercompose/billing_platform_service/docker-compose.yml diff --git a/framework/components/dockercompose/billing_platform_service/billing_platform_service.go b/framework/components/dockercompose/billing_platform_service/billing_platform_service.go new file mode 100644 index 000000000..d80d0ae96 --- /dev/null +++ b/framework/components/dockercompose/billing_platform_service/billing_platform_service.go @@ -0,0 +1,248 @@ +package billing_platform_service + +import ( + "context" + "fmt" + "io" + "net/http" + "os" + "strings" + "time" + + networkTypes "github.com/docker/docker/api/types/network" + "github.com/docker/docker/client" + "github.com/docker/go-connections/nat" + "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-testing-framework/framework" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/modules/compose" + "github.com/testcontainers/testcontainers-go/wait" +) + +type Output struct { + BillingPlatformService *BillingPlatformServiceOutput + Postgres *PostgresOutput +} + +type BillingPlatformServiceOutput struct { + GRPCInternalURL string + GRPCExternalURL string +} + +type PostgresOutput struct { +} + +type Input struct { + ComposeFile string `toml:"compose_file"` + ExtraDockerNetworks []string `toml:"extra_docker_networks"` + Output *Output `toml:"output"` + UseCache bool `toml:"use_cache"` +} + +func defaultBillingPlatformService(in *Input) *Input { + if in.ComposeFile == "" { + in.ComposeFile = "./docker-compose.yml" + } + return in +} + +const ( + DEFAULT_STACK_NAME = "billing-platform-service" + + DEFAULT_BILLING_PLATFORM_SERVICE_GRPC_PORT = "2022" + DEFAULT_BILLING_PLATFORM_SERVICE_SERVICE_NAME = "billing-platform-service" +) + +func New(in *Input) (*Output, error) { + if in == nil { + return nil, errors.New("input is nil") + } + + if in.UseCache { + if in.Output != nil { + return in.Output, nil + } + } + + in = defaultBillingPlatformService(in) + identifier := framework.DefaultTCName(DEFAULT_STACK_NAME) + framework.L.Debug().Str("Compose file", in.ComposeFile). + Msgf("Starting Billing Platform Service stack with identifier %s", + framework.DefaultTCName(DEFAULT_STACK_NAME)) + + cFilePath, fileErr := composeFilePath(in.ComposeFile) + if fileErr != nil { + return nil, errors.Wrap(fileErr, "failed to get compose file path") + } + + stack, stackErr := compose.NewDockerComposeWith( + compose.WithStackFiles(cFilePath), + compose.StackIdentifier(identifier), + ) + if stackErr != nil { + return nil, errors.Wrap(stackErr, "failed to create compose stack for Billing Platform Service") + } + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + defer cancel() + + upErr := stack.Up(ctx) + + if upErr != nil { + return nil, errors.Wrap(upErr, "failed to start stack for Billing Platform Service") + } + + stack.WaitForService(DEFAULT_BILLING_PLATFORM_SERVICE_SERVICE_NAME, + wait.ForAll( + wait.ForLog("GRPC server is live").WithPollInterval(200*time.Millisecond), + wait.ForListeningPort(DEFAULT_BILLING_PLATFORM_SERVICE_GRPC_PORT), + ).WithDeadline(1*time.Minute), + ) + + billingContainer, billingErr := stack.ServiceContainer(ctx, DEFAULT_BILLING_PLATFORM_SERVICE_SERVICE_NAME) + if billingErr != nil { + return nil, errors.Wrap(billingErr, "failed to get billing-platform-service container") + } + + cli, cliErr := client.NewClientWithOpts( + client.FromEnv, + client.WithAPIVersionNegotiation(), + ) + if cliErr != nil { + return nil, errors.Wrap(cliErr, "failed to create docker client") + } + defer cli.Close() + + // so let's try to connect to a Docker network a couple of times, there must be a race condition in Docker + // and even when network sandbox has been created and container is running, this call can still fail + // retrying is simpler than trying to figure out how to correctly wait for the network sandbox to be ready + networks := []string{framework.DefaultNetworkName} + networks = append(networks, in.ExtraDockerNetworks...) + + for _, networkName := range networks { + framework.L.Debug().Msgf("Connecting billing-platform-service to %s network", networkName) + connectContex, connectCancel := context.WithTimeout(ctx, 30*time.Second) + defer connectCancel() + if connectErr := connectNetwork(connectContex, 30*time.Second, cli, billingContainer.ID, networkName, identifier); connectErr != nil { + return nil, errors.Wrapf(connectErr, "failed to connect billing-platform-service to %s network", networkName) + } + // verify that the container is connected to framework's network + inspected, inspectErr := cli.ContainerInspect(ctx, billingContainer.ID) + if inspectErr != nil { + return nil, errors.Wrapf(inspectErr, "failed to inspect container %s", billingContainer.ID) + } + + _, ok := inspected.NetworkSettings.Networks[networkName] + if !ok { + return nil, fmt.Errorf("container %s is NOT on network %s", billingContainer.ID, networkName) + } + + framework.L.Debug().Msgf("Container %s is connected to network %s", billingContainer.ID, networkName) + } + + // get hosts for billing platform service + billingExternalHost, billingExternalHostErr := billingContainer.Host(ctx) + if billingExternalHostErr != nil { + return nil, errors.Wrap(billingExternalHostErr, "failed to get host for Billing Platform Service") + } + + // get mapped port for billing platform service + billingExternalPort, billingExternalPortErr := findMappedPort(ctx, 20*time.Second, billingContainer, DEFAULT_BILLING_PLATFORM_SERVICE_GRPC_PORT) + if billingExternalPortErr != nil { + return nil, errors.Wrap(billingExternalPortErr, "failed to get mapped port for Chip Ingress") + } + + output := &Output{ + BillingPlatformService: &BillingPlatformServiceOutput{ + GRPCInternalURL: fmt.Sprintf("http://%s:%s", DEFAULT_BILLING_PLATFORM_SERVICE_SERVICE_NAME, DEFAULT_BILLING_PLATFORM_SERVICE_GRPC_PORT), + GRPCExternalURL: fmt.Sprintf("http://%s:%s", billingExternalHost, billingExternalPort.Port()), + }, + } + + framework.L.Info().Msg("Chip Ingress stack start") + + return output, nil +} + +func composeFilePath(rawFilePath string) (string, error) { + // if it's not a URL, return it as is and assume it's a local file + if !strings.HasPrefix(rawFilePath, "http") { + return rawFilePath, nil + } + + resp, respErr := http.Get(rawFilePath) + if respErr != nil { + return "", errors.Wrap(respErr, "failed to download docker-compose file") + } + defer resp.Body.Close() + + tempFile, tempErr := os.CreateTemp("", "billing-platform-service-docker-compose-*.yml") + if tempErr != nil { + return "", errors.Wrap(tempErr, "failed to create temp file") + } + defer tempFile.Close() + + _, copyErr := io.Copy(tempFile, resp.Body) + if copyErr != nil { + tempFile.Close() + return "", errors.Wrap(copyErr, "failed to write compose file") + } + + return tempFile.Name(), nil +} + +func findMappedPort(ctx context.Context, timeout time.Duration, container *testcontainers.DockerContainer, port nat.Port) (nat.Port, error) { + forCtx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + tickerInterval := 5 * time.Second + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + + for { + select { + case <-forCtx.Done(): + return "", fmt.Errorf("timeout while waiting for mapped port for %s", port) + case <-ticker.C: + portCtx, portCancel := context.WithTimeout(ctx, tickerInterval) + defer portCancel() + mappedPort, mappedPortErr := container.MappedPort(portCtx, port) + if mappedPortErr != nil { + return "", errors.Wrapf(mappedPortErr, "failed to get mapped port for %s", port) + } + if mappedPort.Port() == "" { + return "", fmt.Errorf("mapped port for %s is empty", port) + } + return mappedPort, nil + } + } +} + +func connectNetwork(connCtx context.Context, timeout time.Duration, dockerClient *client.Client, containerID, networkName, stackIdentifier string) error { + ticker := time.NewTicker(500 * time.Millisecond) + defer ticker.Stop() + + networkCtx, networkCancel := context.WithTimeout(connCtx, timeout) + defer networkCancel() + + for { + select { + case <-networkCtx.Done(): + return fmt.Errorf("timeout while trying to connect billing-platform-service to default network") + case <-ticker.C: + if networkErr := dockerClient.NetworkConnect( + connCtx, + networkName, + containerID, + &networkTypes.EndpointSettings{ + Aliases: []string{stackIdentifier}, + }, + ); networkErr != nil && !strings.Contains(networkErr.Error(), "already exists in network") { + framework.L.Trace().Msgf("failed to connect to default network: %v", networkErr) + continue + } + framework.L.Trace().Msgf("connected to %s network", networkName) + return nil + } + } +} diff --git a/framework/components/dockercompose/billing_platform_service/docker-compose.yml b/framework/components/dockercompose/billing_platform_service/docker-compose.yml new file mode 100644 index 000000000..0c163413d --- /dev/null +++ b/framework/components/dockercompose/billing_platform_service/docker-compose.yml @@ -0,0 +1,74 @@ +services: + billing-platform-service: + restart: on-failure + tty: true + container_name: billing-platform-service + image: ${BILLING_PLATFORM_SERVICE_IMAGE:-} + command: ["grpc-service"] + depends_on: + postgres: + condition: service_healthy + migrations: + condition: service_started + ports: + - "2112:2112" + - "2222:2222" + - "2223:2223" + - "2257:2257" + environment: + PROMETHEUS_PORT: 2112 + BILLING_SERVER_PORT: 2222 + CREDIT_RESERVATION_SERVER_PORT: 2223 + WORKFLOW_OWNERSHIP_PROOF_SERVER_PORT: 2257 + WORKFLOW_OWNERSHIP_PROOF_SERVER_HOST: 0.0.0.0 + STREAMS_API_URL: ${STREAMS_API_URL} + STREAMS_API_KEY: ${STREAMS_API_KEY} + STREAMS_API_SECRET: ${STREAMS_API_SECRET} + DB_HOST: postgres + DB_PORT: 5432 + DB_NAME: billing_platform + DB_USERNAME: postgres + DB_PASSWORD: postgres + healthcheck: + test: ["CMD", "grpc_health_probe", "-addr=localhost:2222"] + interval: 200ms + timeout: 10s + retries: 3 + + postgres: + image: postgres:16-alpine + container_name: postgres-billing-platform + restart: always + environment: + POSTGRES_HOST_AUTH_METHOD: trust + POSTGRES_DB: billing_platform + POSTGRES_HOST: postgres + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD","pg_isready","-U","${POSTGRES_USER}","-d","${POSTGRES_DB}","-h","${POSTGRES_HOST}"] + interval: 5s + timeout: 10s + retries: 3 + ports: + - "5432:5432" + + migrations: + image: ${BILLING_PLATFORM_SERVICE_MIGRATION_IMAGE:-} + container_name: db-migrations-billing-platform + restart: on-failure + environment: + DBMATE_NO_DUMP_SCHEMA: true + DBMATE_WAIT: true + DATABASE_URL: postgres://postgres:postgres@postgres:postgres/billing_platform + networks: + - backend + depends_on: + postgres: + condition: service_healthy + entrypoint: + - dbmate + - up + - -- + - --url=${DATABASE_URL} + - --migrations-dir=/db From 14888c657336750a4f38611c2901d8340da03e43 Mon Sep 17 00:00:00 2001 From: Clement Erena Date: Mon, 4 Aug 2025 13:36:56 +0200 Subject: [PATCH 2/8] refactor --- .../billing_platform_service.go | 113 ++---------------- .../components/dockercompose/utils/docker.go | 105 ++++++++++++++++ 2 files changed, 118 insertions(+), 100 deletions(-) create mode 100644 framework/components/dockercompose/utils/docker.go diff --git a/framework/components/dockercompose/billing_platform_service/billing_platform_service.go b/framework/components/dockercompose/billing_platform_service/billing_platform_service.go index d80d0ae96..be8a8e312 100644 --- a/framework/components/dockercompose/billing_platform_service/billing_platform_service.go +++ b/framework/components/dockercompose/billing_platform_service/billing_platform_service.go @@ -3,18 +3,12 @@ package billing_platform_service import ( "context" "fmt" - "io" - "net/http" - "os" - "strings" "time" - networkTypes "github.com/docker/docker/api/types/network" "github.com/docker/docker/client" - "github.com/docker/go-connections/nat" "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-testing-framework/framework" - "github.com/testcontainers/testcontainers-go" + "github.com/smartcontractkit/chainlink-testing-framework/framework/components/dockercompose/utils" "github.com/testcontainers/testcontainers-go/modules/compose" "github.com/testcontainers/testcontainers-go/wait" ) @@ -30,6 +24,7 @@ type BillingPlatformServiceOutput struct { } type PostgresOutput struct { + DSN string } type Input struct { @@ -58,10 +53,8 @@ func New(in *Input) (*Output, error) { return nil, errors.New("input is nil") } - if in.UseCache { - if in.Output != nil { - return in.Output, nil - } + if in.UseCache && in.Output != nil { + return in.Output, nil } in = defaultBillingPlatformService(in) @@ -70,7 +63,7 @@ func New(in *Input) (*Output, error) { Msgf("Starting Billing Platform Service stack with identifier %s", framework.DefaultTCName(DEFAULT_STACK_NAME)) - cFilePath, fileErr := composeFilePath(in.ComposeFile) + cFilePath, fileErr := utils.ComposeFilePath(in.ComposeFile, DEFAULT_STACK_NAME) if fileErr != nil { return nil, errors.Wrap(fileErr, "failed to get compose file path") } @@ -121,9 +114,9 @@ func New(in *Input) (*Output, error) { for _, networkName := range networks { framework.L.Debug().Msgf("Connecting billing-platform-service to %s network", networkName) - connectContex, connectCancel := context.WithTimeout(ctx, 30*time.Second) + connectCtx, connectCancel := context.WithTimeout(ctx, 30*time.Second) defer connectCancel() - if connectErr := connectNetwork(connectContex, 30*time.Second, cli, billingContainer.ID, networkName, identifier); connectErr != nil { + if connectErr := utils.ConnectNetwork(connectCtx, 30*time.Second, cli, billingContainer.ID, networkName, identifier); connectErr != nil { return nil, errors.Wrapf(connectErr, "failed to connect billing-platform-service to %s network", networkName) } // verify that the container is connected to framework's network @@ -141,13 +134,13 @@ func New(in *Input) (*Output, error) { } // get hosts for billing platform service - billingExternalHost, billingExternalHostErr := billingContainer.Host(ctx) + billingExternalHost, billingExternalHostErr := utils.GetContainerHost(ctx, billingContainer) if billingExternalHostErr != nil { return nil, errors.Wrap(billingExternalHostErr, "failed to get host for Billing Platform Service") } // get mapped port for billing platform service - billingExternalPort, billingExternalPortErr := findMappedPort(ctx, 20*time.Second, billingContainer, DEFAULT_BILLING_PLATFORM_SERVICE_GRPC_PORT) + billingExternalPort, billingExternalPortErr := utils.FindMappedPort(ctx, 20*time.Second, billingContainer, DEFAULT_BILLING_PLATFORM_SERVICE_GRPC_PORT) if billingExternalPortErr != nil { return nil, errors.Wrap(billingExternalPortErr, "failed to get mapped port for Chip Ingress") } @@ -157,92 +150,12 @@ func New(in *Input) (*Output, error) { GRPCInternalURL: fmt.Sprintf("http://%s:%s", DEFAULT_BILLING_PLATFORM_SERVICE_SERVICE_NAME, DEFAULT_BILLING_PLATFORM_SERVICE_GRPC_PORT), GRPCExternalURL: fmt.Sprintf("http://%s:%s", billingExternalHost, billingExternalPort.Port()), }, - } - - framework.L.Info().Msg("Chip Ingress stack start") - - return output, nil -} - -func composeFilePath(rawFilePath string) (string, error) { - // if it's not a URL, return it as is and assume it's a local file - if !strings.HasPrefix(rawFilePath, "http") { - return rawFilePath, nil - } - - resp, respErr := http.Get(rawFilePath) - if respErr != nil { - return "", errors.Wrap(respErr, "failed to download docker-compose file") - } - defer resp.Body.Close() - - tempFile, tempErr := os.CreateTemp("", "billing-platform-service-docker-compose-*.yml") - if tempErr != nil { - return "", errors.Wrap(tempErr, "failed to create temp file") - } - defer tempFile.Close() + Postgres: &PostgresOutput{ - _, copyErr := io.Copy(tempFile, resp.Body) - if copyErr != nil { - tempFile.Close() - return "", errors.Wrap(copyErr, "failed to write compose file") - } - - return tempFile.Name(), nil -} - -func findMappedPort(ctx context.Context, timeout time.Duration, container *testcontainers.DockerContainer, port nat.Port) (nat.Port, error) { - forCtx, cancel := context.WithTimeout(ctx, timeout) - defer cancel() - - tickerInterval := 5 * time.Second - ticker := time.NewTicker(5 * time.Second) - defer ticker.Stop() - - for { - select { - case <-forCtx.Done(): - return "", fmt.Errorf("timeout while waiting for mapped port for %s", port) - case <-ticker.C: - portCtx, portCancel := context.WithTimeout(ctx, tickerInterval) - defer portCancel() - mappedPort, mappedPortErr := container.MappedPort(portCtx, port) - if mappedPortErr != nil { - return "", errors.Wrapf(mappedPortErr, "failed to get mapped port for %s", port) - } - if mappedPort.Port() == "" { - return "", fmt.Errorf("mapped port for %s is empty", port) - } - return mappedPort, nil } } -} -func connectNetwork(connCtx context.Context, timeout time.Duration, dockerClient *client.Client, containerID, networkName, stackIdentifier string) error { - ticker := time.NewTicker(500 * time.Millisecond) - defer ticker.Stop() - - networkCtx, networkCancel := context.WithTimeout(connCtx, timeout) - defer networkCancel() - - for { - select { - case <-networkCtx.Done(): - return fmt.Errorf("timeout while trying to connect billing-platform-service to default network") - case <-ticker.C: - if networkErr := dockerClient.NetworkConnect( - connCtx, - networkName, - containerID, - &networkTypes.EndpointSettings{ - Aliases: []string{stackIdentifier}, - }, - ); networkErr != nil && !strings.Contains(networkErr.Error(), "already exists in network") { - framework.L.Trace().Msgf("failed to connect to default network: %v", networkErr) - continue - } - framework.L.Trace().Msgf("connected to %s network", networkName) - return nil - } - } + framework.L.Info().Msg("Billing Platform Service stack start") + + return output, nil } diff --git a/framework/components/dockercompose/utils/docker.go b/framework/components/dockercompose/utils/docker.go new file mode 100644 index 000000000..520f401af --- /dev/null +++ b/framework/components/dockercompose/utils/docker.go @@ -0,0 +1,105 @@ +package utils + +import ( + "context" + "fmt" + "io" + "net/http" + "os" + "strings" + "time" + + networkTypes "github.com/docker/docker/api/types/network" + "github.com/docker/docker/client" + "github.com/docker/go-connections/nat" + "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-testing-framework/framework" + "github.com/testcontainers/testcontainers-go" +) + +func ComposeFilePath(rawFilePath string, serviceName string) (string, error) { + // if it's not a URL, return it as is and assume it's a local file + if !strings.HasPrefix(rawFilePath, "http") { + return rawFilePath, nil + } + + resp, respErr := http.Get(rawFilePath) + if respErr != nil { + return "", errors.Wrap(respErr, "failed to download docker-compose file") + } + defer resp.Body.Close() + + tempFile, tempErr := os.CreateTemp("", serviceName+"-docker-compose-*.yml") + if tempErr != nil { + return "", errors.Wrap(tempErr, "failed to create temp file") + } + defer tempFile.Close() + + _, copyErr := io.Copy(tempFile, resp.Body) + if copyErr != nil { + tempFile.Close() + return "", errors.Wrap(copyErr, "failed to write compose file") + } + + return tempFile.Name(), nil +} + +func GetContainerHost(ctx context.Context, container *testcontainers.DockerContainer) (string, error) { + return container.Host(ctx) +} + +func FindMappedPort(ctx context.Context, timeout time.Duration, container *testcontainers.DockerContainer, port nat.Port) (nat.Port, error) { + forCtx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + tickerInterval := 5 * time.Second + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + + for { + select { + case <-forCtx.Done(): + return "", fmt.Errorf("timeout while waiting for mapped port for %s", port) + case <-ticker.C: + portCtx, portCancel := context.WithTimeout(ctx, tickerInterval) + defer portCancel() + mappedPort, mappedPortErr := container.MappedPort(portCtx, port) + if mappedPortErr != nil { + return "", errors.Wrapf(mappedPortErr, "failed to get mapped port for %s", port) + } + if mappedPort.Port() == "" { + return "", fmt.Errorf("mapped port for %s is empty", port) + } + return mappedPort, nil + } + } +} + +func ConnectNetwork(connCtx context.Context, timeout time.Duration, dockerClient *client.Client, containerID, networkName, stackIdentifier string) error { + ticker := time.NewTicker(500 * time.Millisecond) + defer ticker.Stop() + + networkCtx, networkCancel := context.WithTimeout(connCtx, timeout) + defer networkCancel() + + for { + select { + case <-networkCtx.Done(): + return fmt.Errorf("timeout while trying to connect billing-platform-service to default network") + case <-ticker.C: + if networkErr := dockerClient.NetworkConnect( + connCtx, + networkName, + containerID, + &networkTypes.EndpointSettings{ + Aliases: []string{stackIdentifier}, + }, + ); networkErr != nil && !strings.Contains(networkErr.Error(), "already exists in network") { + framework.L.Trace().Msgf("failed to connect to default network: %v", networkErr) + continue + } + framework.L.Trace().Msgf("connected to %s network", networkName) + return nil + } + } +} From f795c807878e0b03a85577c7faad6f379d3f464e Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Tue, 9 Sep 2025 10:03:01 -0600 Subject: [PATCH 3/8] update billing with env vars and input configs --- .../billing_platform_service.go | 151 +++++++++++++++--- .../docker-compose.yml | 77 +++++---- framework/components/dockercompose/go.mod | 3 +- framework/components/dockercompose/go.sum | 2 + 4 files changed, 181 insertions(+), 52 deletions(-) diff --git a/framework/components/dockercompose/billing_platform_service/billing_platform_service.go b/framework/components/dockercompose/billing_platform_service/billing_platform_service.go index be8a8e312..32bb8dca0 100644 --- a/framework/components/dockercompose/billing_platform_service/billing_platform_service.go +++ b/framework/components/dockercompose/billing_platform_service/billing_platform_service.go @@ -3,24 +3,35 @@ package billing_platform_service import ( "context" "fmt" + "os" + "strconv" + "strings" "time" "github.com/docker/docker/client" + "github.com/docker/go-connections/nat" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-testing-framework/framework" - "github.com/smartcontractkit/chainlink-testing-framework/framework/components/dockercompose/utils" + "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/modules/compose" "github.com/testcontainers/testcontainers-go/wait" + + "github.com/smartcontractkit/chainlink-testing-framework/framework" + "github.com/smartcontractkit/chainlink-testing-framework/framework/components/dockercompose/utils" + "github.com/smartcontractkit/freeport" ) +const DefaultPostgresDSN = "postgres://postgres:postgres@postgres:5432/billing_platform?sslmode=disable" + type Output struct { BillingPlatformService *BillingPlatformServiceOutput Postgres *PostgresOutput } type BillingPlatformServiceOutput struct { - GRPCInternalURL string - GRPCExternalURL string + BillingGRPCInternalURL string + BillingGRPCExternalURL string + CreditGRPCInternalURL string + CreditGRPCExternalURL string } type PostgresOutput struct { @@ -28,10 +39,18 @@ type PostgresOutput struct { } type Input struct { - ComposeFile string `toml:"compose_file"` - ExtraDockerNetworks []string `toml:"extra_docker_networks"` - Output *Output `toml:"output"` - UseCache bool `toml:"use_cache"` + ComposeFile string `toml:"compose_file"` + ExtraDockerNetworks []string `toml:"extra_docker_networks"` + Output *Output `toml:"output"` + UseCache bool `toml:"use_cache"` + ChainSelector uint64 `toml:"chain_selector"` + StreamsAPIURL string `toml:"streams_api_url"` + StreamsAPIKey string `toml:"streams_api_key"` + StreamsAPISecret string `toml:"streams_api_secret"` + RPCURL string `toml:"rpc_url"` + WorkflowRegistryAddress string `toml:"workflow_registry_address"` + CapabilitiesRegistryAddress string `toml:"capabilities_registry_address"` + WorkflowOwners []string `toml:"workflow_owners"` } func defaultBillingPlatformService(in *Input) *Input { @@ -44,8 +63,11 @@ func defaultBillingPlatformService(in *Input) *Input { const ( DEFAULT_STACK_NAME = "billing-platform-service" - DEFAULT_BILLING_PLATFORM_SERVICE_GRPC_PORT = "2022" - DEFAULT_BILLING_PLATFORM_SERVICE_SERVICE_NAME = "billing-platform-service" + DEFAULT_BILLING_PLATFORM_SERVICE_BILLING_GRPC_PORT = "2222" + DEFAULT_BILLING_PLATFORM_SERVICE_CREDIT_GRPC_PORT = "2223" + DEFAULT_POSTGRES_PORT = "5432" + DEFAULT_BILLING_PLATFORM_SERVICE_SERVICE_NAME = "billing-platform-service" + DEFAULT_POSTGRES_SERVICE_NAME = "postgres" ) func New(in *Input) (*Output, error) { @@ -79,7 +101,48 @@ func New(in *Input) (*Output, error) { ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) defer cancel() - upErr := stack.Up(ctx) + // Start the stackwith all environment variables from the host process + // set development defaults for necessary environment variables and allow them to be overridden by the host process + envVars := make(map[string]string) + + envVars["MAINNET_WORKFLOW_REGISTRY_CHAIN_SELECTOR"] = strconv.FormatUint(in.ChainSelector, 10) + envVars["MAINNET_WORKFLOW_REGISTRY_CONTRACT_ADDRESS"] = in.WorkflowRegistryAddress + envVars["MAINNET_WORKFLOW_REGISTRY_RPC_URL"] = in.RPCURL + envVars["MAINNET_WORKFLOW_REGISTRY_FINALITY_DEPTH"] = "0" // Instant finality on devnet + envVars["KMS_PROOF_SIGNING_KEY_ID"] = "00000000-0000-0000-0000-000000000001" // provisioned via LocalStack + envVars["VERIFIER_INITIAL_INTERVAL"] = "0s" // reduced to force verifier to start immediately in integration tests + envVars["VERIFIER_MAXIMUM_INTERVAL"] = "1s" // reduced to force verifier to start immediately in integration tests + envVars["LINKING_REQUEST_COOLDOWN"] = "0s" // reduced to force consequtive linking requests to be processed immediately in integration tests + + envVars["MAINNET_CAPABILITIES_REGISTRY_CHAIN_SELECTOR"] = strconv.FormatUint(in.ChainSelector, 10) + envVars["MAINNET_CAPABILITIES_REGISTRY_CONTRACT_ADDRESS"] = in.CapabilitiesRegistryAddress + envVars["MAINNET_CAPABILITIES_REGISTRY_RPC_URL"] = in.RPCURL + envVars["MAINNET_CAPABILITIES_REGISTRY_FINALITY_DEPTH"] = "10" // Arbitrary value, adjust as needed + + envVars["TEST_OWNERS"] = strings.Join(in.WorkflowOwners, ",") + envVars["STREAMS_API_URL"] = in.StreamsAPIURL + envVars["STREAMS_API_KEY"] = in.StreamsAPIKey + envVars["STREAMS_API_SECRET"] = in.StreamsAPISecret + + for _, env := range os.Environ() { + pair := strings.SplitN(env, "=", 2) + if len(pair) == 2 { + envVars[pair[0]] = pair[1] + } + } + + // set these env vars after reading env vars from host + port, err := freeport.Take(1) + if err != nil { + return nil, errors.Wrap(err, "failed to get free port for Billing Platform Service postgres") + } + + envVars["POSTGRES_PORT"] = strconv.FormatInt(int64(port[0]), 10) + envVars["DEFAULT_DSN"] = DefaultPostgresDSN + + upErr := stack. + WithEnv(envVars). + Up(ctx) if upErr != nil { return nil, errors.Wrap(upErr, "failed to start stack for Billing Platform Service") @@ -88,7 +151,8 @@ func New(in *Input) (*Output, error) { stack.WaitForService(DEFAULT_BILLING_PLATFORM_SERVICE_SERVICE_NAME, wait.ForAll( wait.ForLog("GRPC server is live").WithPollInterval(200*time.Millisecond), - wait.ForListeningPort(DEFAULT_BILLING_PLATFORM_SERVICE_GRPC_PORT), + wait.ForListeningPort(DEFAULT_BILLING_PLATFORM_SERVICE_BILLING_GRPC_PORT), + wait.ForListeningPort(DEFAULT_BILLING_PLATFORM_SERVICE_CREDIT_GRPC_PORT), ).WithDeadline(1*time.Minute), ) @@ -97,6 +161,11 @@ func New(in *Input) (*Output, error) { return nil, errors.Wrap(billingErr, "failed to get billing-platform-service container") } + postgresContainer, postgresErr := stack.ServiceContainer(ctx, DEFAULT_POSTGRES_SERVICE_NAME) + if postgresErr != nil { + return nil, errors.Wrap(postgresErr, "failed to get postgres container") + } + cli, cliErr := client.NewClientWithOpts( client.FromEnv, client.WithAPIVersionNegotiation(), @@ -139,23 +208,61 @@ func New(in *Input) (*Output, error) { return nil, errors.Wrap(billingExternalHostErr, "failed to get host for Billing Platform Service") } - // get mapped port for billing platform service - billingExternalPort, billingExternalPortErr := utils.FindMappedPort(ctx, 20*time.Second, billingContainer, DEFAULT_BILLING_PLATFORM_SERVICE_GRPC_PORT) - if billingExternalPortErr != nil { - return nil, errors.Wrap(billingExternalPortErr, "failed to get mapped port for Chip Ingress") + // get hosts for billing platform service + postgresExternalHost, postgresExternalHostErr := utils.GetContainerHost(ctx, postgresContainer) + if postgresExternalHostErr != nil { + return nil, errors.Wrap(postgresExternalHostErr, "failed to get host for postgres") + } + + // get mapped ports for billing platform service + serviceOutput, err := getExternalPorts(ctx, billingExternalHost, billingContainer) + if err != nil { + return nil, errors.Wrap(err, "failed to get mapped port for Billing Platform Service") + } + + externalPostgresPort, err := utils.FindMappedPort(ctx, 20*time.Second, postgresContainer, nat.Port(DEFAULT_POSTGRES_PORT+"/tcp")) + if err != nil { + return nil, errors.Wrap(err, "failed to get mapped port for postgres") } output := &Output{ - BillingPlatformService: &BillingPlatformServiceOutput{ - GRPCInternalURL: fmt.Sprintf("http://%s:%s", DEFAULT_BILLING_PLATFORM_SERVICE_SERVICE_NAME, DEFAULT_BILLING_PLATFORM_SERVICE_GRPC_PORT), - GRPCExternalURL: fmt.Sprintf("http://%s:%s", billingExternalHost, billingExternalPort.Port()), - }, + BillingPlatformService: serviceOutput, Postgres: &PostgresOutput{ - - } + DSN: fmt.Sprintf("postgres://postgres:postgres@%s:%s/billing_platform", postgresExternalHost, externalPostgresPort.Port()), + }, } framework.L.Info().Msg("Billing Platform Service stack start") return output, nil } + +func getExternalPorts(ctx context.Context, billingExternalHost string, billingContainer *testcontainers.DockerContainer) (*BillingPlatformServiceOutput, error) { + ports := map[string]nat.Port{ + "billing": DEFAULT_BILLING_PLATFORM_SERVICE_BILLING_GRPC_PORT, + "credit": DEFAULT_BILLING_PLATFORM_SERVICE_CREDIT_GRPC_PORT, + } + + output := BillingPlatformServiceOutput{} + + for name, defaultPort := range ports { + externalPort, err := utils.FindMappedPort(ctx, 20*time.Second, billingContainer, defaultPort) + if err != nil { + return nil, errors.Wrap(err, "failed to get mapped port for Billing Platform Service") + } + + internal := fmt.Sprintf("http://%s:%s", DEFAULT_BILLING_PLATFORM_SERVICE_SERVICE_NAME, defaultPort) + external := fmt.Sprintf("http://%s:%s", billingExternalHost, externalPort.Port()) + + switch name { + case "billing": + output.BillingGRPCInternalURL = internal + output.BillingGRPCExternalURL = external + case "credit": + output.CreditGRPCInternalURL = internal + output.CreditGRPCExternalURL = external + } + } + + return &output, nil +} diff --git a/framework/components/dockercompose/billing_platform_service/docker-compose.yml b/framework/components/dockercompose/billing_platform_service/docker-compose.yml index 0c163413d..b0294c800 100644 --- a/framework/components/dockercompose/billing_platform_service/docker-compose.yml +++ b/framework/components/dockercompose/billing_platform_service/docker-compose.yml @@ -1,34 +1,52 @@ services: + billing-platform-service: - restart: on-failure - tty: true + image: ${BILLING_PLATFORM_SERVICE_IMAGE:-billing-platform-service:local-cre} container_name: billing-platform-service - image: ${BILLING_PLATFORM_SERVICE_IMAGE:-} - command: ["grpc-service"] depends_on: postgres: condition: service_healthy migrations: condition: service_started - ports: - - "2112:2112" - - "2222:2222" - - "2223:2223" - - "2257:2257" + restart: on-failure + tty: true + command: ["grpc", "billing", "reserve"] environment: + DISABLE_AUTH: true PROMETHEUS_PORT: 2112 BILLING_SERVER_PORT: 2222 CREDIT_RESERVATION_SERVER_PORT: 2223 - WORKFLOW_OWNERSHIP_PROOF_SERVER_PORT: 2257 WORKFLOW_OWNERSHIP_PROOF_SERVER_HOST: 0.0.0.0 - STREAMS_API_URL: ${STREAMS_API_URL} - STREAMS_API_KEY: ${STREAMS_API_KEY} - STREAMS_API_SECRET: ${STREAMS_API_SECRET} + MAINNET_WORKFLOW_REGISTRY_CHAIN_SELECTOR: ${MAINNET_WORKFLOW_REGISTRY_CHAIN_SELECTOR:-} + TESTNET_WORKFLOW_REGISTRY_CHAIN_SELECTOR: ${MAINNET_WORKFLOW_REGISTRY_CHAIN_SELECTOR:-} + MAINNET_WORKFLOW_REGISTRY_CONTRACT_ADDRESS: ${MAINNET_WORKFLOW_REGISTRY_CONTRACT_ADDRESS:-} + TESTNET_WORKFLOW_REGISTRY_CONTRACT_ADDRESS: ${MAINNET_WORKFLOW_REGISTRY_CONTRACT_ADDRESS:-} + MAINNET_WORKFLOW_REGISTRY_RPC_URL: ${MAINNET_WORKFLOW_REGISTRY_RPC_URL:-} + TESTNET_WORKFLOW_REGISTRY_RPC_URL: ${MAINNET_WORKFLOW_REGISTRY_RPC_URL:-} + MAINNET_WORKFLOW_REGISTRY_FINALITY_DEPTH: ${MAINNET_WORKFLOW_REGISTRY_FINALITY_DEPTH:-} + KMS_PROOF_SIGNING_KEY_ID: ${KMS_PROOF_SIGNING_KEY_ID:-} + VERIFIER_INITIAL_INTERVAL: ${VERIFIER_INITIAL_INTERVAL:-} + VERIFIER_MAXIMUM_INTERVAL: ${VERIFIER_MAXIMUM_INTERVAL:-} + LINKING_REQUEST_COOLDOWN: ${LINKING_REQUEST_COOLDOWN:-} + MAINNET_CAPABILITIES_REGISTRY_CHAIN_SELECTOR: ${MAINNET_CAPABILITIES_REGISTRY_CHAIN_SELECTOR:-} + TESTNET_CAPABILITIES_REGISTRY_CHAIN_SELECTOR: ${MAINNET_CAPABILITIES_REGISTRY_CHAIN_SELECTOR:-} + MAINNET_CAPABILITIES_REGISTRY_CONTRACT_ADDRESS: ${MAINNET_CAPABILITIES_REGISTRY_CONTRACT_ADDRESS:-} + MAINNET_CAPABILITIES_REGISTRY_RPC_URL: ${MAINNET_CAPABILITIES_REGISTRY_RPC_URL:-} + TESTNET_CAPABILITIES_REGISTRY_RPC_URL: ${MAINNET_CAPABILITIES_REGISTRY_RPC_URL:-} + MAINNET_CAPABILITIES_REGISTRY_FINALITY_DEPTH: ${MAINNET_CAPABILITIES_REGISTRY_FINALITY_DEPTH:-} + TEST_OWNERS: ${TEST_OWNERS:-} + STREAMS_API_URL: ${STREAMS_API_URL:-} + STREAMS_API_KEY: ${STREAMS_API_KEY:-} + STREAMS_API_SECRET: ${STREAMS_API_SECRET:-} DB_HOST: postgres DB_PORT: 5432 DB_NAME: billing_platform DB_USERNAME: postgres DB_PASSWORD: postgres + ports: + - "2112:2112" + - "2222:2222" + - "2223:2223" healthcheck: test: ["CMD", "grpc_health_probe", "-addr=localhost:2222"] interval: 200ms @@ -45,30 +63,31 @@ services: POSTGRES_HOST: postgres POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres + ports: + - "${POSTGRES_PORT:-5432}:5432" healthcheck: test: ["CMD","pg_isready","-U","${POSTGRES_USER}","-d","${POSTGRES_DB}","-h","${POSTGRES_HOST}"] interval: 5s timeout: 10s retries: 3 - ports: - - "5432:5432" migrations: - image: ${BILLING_PLATFORM_SERVICE_MIGRATION_IMAGE:-} + image: ${BILLING_PLATFORM_SERVICE_IMAGE:-billing-platform-service:local-cre} container_name: db-migrations-billing-platform - restart: on-failure - environment: - DBMATE_NO_DUMP_SCHEMA: true - DBMATE_WAIT: true - DATABASE_URL: postgres://postgres:postgres@postgres:postgres/billing_platform - networks: - - backend depends_on: postgres: condition: service_healthy - entrypoint: - - dbmate - - up - - -- - - --url=${DATABASE_URL} - - --migrations-dir=/db + restart: on-failure + command: ["db", "create-and-migrate", "--url", "${DEFAULT_DSN:-}"] + + populate_test_data: + image: ${BILLING_PLATFORM_SERVICE_IMAGE:-billing-platform-service:local-cre} + container_name: populate-data-billing-platform + depends_on: + billing-platform-service: + condition: service_started + restart: on-failure + command: ["db", "populate-data", "--environment=local", "--billing-client-url=billing-platform-service:2222", "--simple-linking", "--dsn=${DEFAULT_DSN:-}"] + environment: + TEST_OWNERS: ${TEST_OWNERS:-} + MAINNET_CAPABILITIES_REGISTRY_CHAIN_SELECTOR: ${MAINNET_CAPABILITIES_REGISTRY_CHAIN_SELECTOR:-} diff --git a/framework/components/dockercompose/go.mod b/framework/components/dockercompose/go.mod index 0f727901c..586062bf0 100644 --- a/framework/components/dockercompose/go.mod +++ b/framework/components/dockercompose/go.mod @@ -8,9 +8,11 @@ require ( github.com/avast/retry-go/v4 v4.6.1 github.com/confluentinc/confluent-kafka-go v1.9.2 github.com/docker/docker v28.0.4+incompatible + github.com/docker/go-connections v0.5.0 github.com/google/go-github/v72 v72.0.0 github.com/pkg/errors v0.9.1 github.com/smartcontractkit/chainlink-testing-framework/framework v0.0.0-00010101000000-000000000000 + github.com/smartcontractkit/freeport v0.1.2 github.com/testcontainers/testcontainers-go v0.37.0 github.com/testcontainers/testcontainers-go/modules/compose v0.37.0 golang.org/x/oauth2 v0.25.0 @@ -66,7 +68,6 @@ require ( github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.2 // indirect github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect - github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/ebitengine/purego v0.8.2 // indirect diff --git a/framework/components/dockercompose/go.sum b/framework/components/dockercompose/go.sum index 6b714d92d..fc11981c7 100644 --- a/framework/components/dockercompose/go.sum +++ b/framework/components/dockercompose/go.sum @@ -567,6 +567,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= +github.com/smartcontractkit/freeport v0.1.2 h1:xMZ0UFHmjfB4MwbDANae3RS7UKt7OJ0JVqhjPSXdKVk= +github.com/smartcontractkit/freeport v0.1.2/go.mod h1:T4zH9R8R8lVWKfU7tUvYz2o2jMv1OpGCdpY2j2QZXzU= github.com/spdx/tools-golang v0.5.3 h1:ialnHeEYUC4+hkm5vJm4qz2x+oEJbS0mAMFrNXdQraY= github.com/spdx/tools-golang v0.5.3/go.mod h1:/ETOahiAo96Ob0/RAIBmFZw6XN0yTnyr/uFZm2NTMhI= github.com/spf13/cast v0.0.0-20150508191742-4d07383ffe94 h1:JmfC365KywYwHB946TTiQWEb8kqPY+pybPLoGE9GgVk= From d467a8b0e25088057b0eaae132df85abc03e0491 Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Tue, 9 Sep 2025 14:29:10 -0600 Subject: [PATCH 4/8] address comments --- .../billing_platform_service.go | 30 ++++++++++++------- .../docker-compose.yml | 4 +-- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/framework/components/dockercompose/billing_platform_service/billing_platform_service.go b/framework/components/dockercompose/billing_platform_service/billing_platform_service.go index 32bb8dca0..685cc9c2b 100644 --- a/framework/components/dockercompose/billing_platform_service/billing_platform_service.go +++ b/framework/components/dockercompose/billing_platform_service/billing_platform_service.go @@ -61,8 +61,6 @@ func defaultBillingPlatformService(in *Input) *Input { } const ( - DEFAULT_STACK_NAME = "billing-platform-service" - DEFAULT_BILLING_PLATFORM_SERVICE_BILLING_GRPC_PORT = "2222" DEFAULT_BILLING_PLATFORM_SERVICE_CREDIT_GRPC_PORT = "2223" DEFAULT_POSTGRES_PORT = "5432" @@ -70,6 +68,14 @@ const ( DEFAULT_POSTGRES_SERVICE_NAME = "postgres" ) +// New starts a Billing Platform Service stack using docker-compose. Various env vars are set to sensible defaults and +// input values, but can be overridden by the host process env vars if needed. +// +// Import env vars that can be set to override defaults: +// - TEST_OWNERS = comma separated list of workflow owners +// - STREAMS_API_URL = URL for the Streams API; can use a mock server if needed +// - STREAMS_API_KEY = API key if using a staging or prod Streams API +// - STREAMS_API_SECRET = API secret if using a staging or prod Streams API func New(in *Input) (*Output, error) { if in == nil { return nil, errors.New("input is nil") @@ -80,12 +86,12 @@ func New(in *Input) (*Output, error) { } in = defaultBillingPlatformService(in) - identifier := framework.DefaultTCName(DEFAULT_STACK_NAME) + identifier := framework.DefaultTCName(DEFAULT_BILLING_PLATFORM_SERVICE_SERVICE_NAME) framework.L.Debug().Str("Compose file", in.ComposeFile). Msgf("Starting Billing Platform Service stack with identifier %s", - framework.DefaultTCName(DEFAULT_STACK_NAME)) + framework.DefaultTCName(DEFAULT_BILLING_PLATFORM_SERVICE_SERVICE_NAME)) - cFilePath, fileErr := utils.ComposeFilePath(in.ComposeFile, DEFAULT_STACK_NAME) + cFilePath, fileErr := utils.ComposeFilePath(in.ComposeFile, DEFAULT_BILLING_PLATFORM_SERVICE_SERVICE_NAME) if fileErr != nil { return nil, errors.Wrap(fileErr, "failed to get compose file path") } @@ -105,6 +111,8 @@ func New(in *Input) (*Output, error) { // set development defaults for necessary environment variables and allow them to be overridden by the host process envVars := make(map[string]string) + envVars["BILLING_SERVICE_PORT"] = DEFAULT_BILLING_PLATFORM_SERVICE_BILLING_GRPC_PORT + envVars["CREDIT_RESERVATION_SERVICE_PORT"] = DEFAULT_BILLING_PLATFORM_SERVICE_CREDIT_GRPC_PORT envVars["MAINNET_WORKFLOW_REGISTRY_CHAIN_SELECTOR"] = strconv.FormatUint(in.ChainSelector, 10) envVars["MAINNET_WORKFLOW_REGISTRY_CONTRACT_ADDRESS"] = in.WorkflowRegistryAddress envVars["MAINNET_WORKFLOW_REGISTRY_RPC_URL"] = in.RPCURL @@ -151,8 +159,8 @@ func New(in *Input) (*Output, error) { stack.WaitForService(DEFAULT_BILLING_PLATFORM_SERVICE_SERVICE_NAME, wait.ForAll( wait.ForLog("GRPC server is live").WithPollInterval(200*time.Millisecond), - wait.ForListeningPort(DEFAULT_BILLING_PLATFORM_SERVICE_BILLING_GRPC_PORT), - wait.ForListeningPort(DEFAULT_BILLING_PLATFORM_SERVICE_CREDIT_GRPC_PORT), + wait.ForListeningPort(nat.Port(envVars["BILLING_SERVICE_PORT"])), + wait.ForListeningPort(nat.Port(envVars["CREDIT_RESERVATION_SERVICE_PORT"])), ).WithDeadline(1*time.Minute), ) @@ -215,7 +223,7 @@ func New(in *Input) (*Output, error) { } // get mapped ports for billing platform service - serviceOutput, err := getExternalPorts(ctx, billingExternalHost, billingContainer) + serviceOutput, err := getExternalPorts(ctx, billingExternalHost, envVars, billingContainer) if err != nil { return nil, errors.Wrap(err, "failed to get mapped port for Billing Platform Service") } @@ -237,10 +245,10 @@ func New(in *Input) (*Output, error) { return output, nil } -func getExternalPorts(ctx context.Context, billingExternalHost string, billingContainer *testcontainers.DockerContainer) (*BillingPlatformServiceOutput, error) { +func getExternalPorts(ctx context.Context, billingExternalHost string, envVars map[string]string, billingContainer *testcontainers.DockerContainer) (*BillingPlatformServiceOutput, error) { ports := map[string]nat.Port{ - "billing": DEFAULT_BILLING_PLATFORM_SERVICE_BILLING_GRPC_PORT, - "credit": DEFAULT_BILLING_PLATFORM_SERVICE_CREDIT_GRPC_PORT, + "billing": nat.Port(envVars["BILLING_SERVICE_PORT"]), + "credit": nat.Port(envVars["CREDIT_RESERVATION_SERVICE_PORT"]), } output := BillingPlatformServiceOutput{} diff --git a/framework/components/dockercompose/billing_platform_service/docker-compose.yml b/framework/components/dockercompose/billing_platform_service/docker-compose.yml index b0294c800..df7c3b27c 100644 --- a/framework/components/dockercompose/billing_platform_service/docker-compose.yml +++ b/framework/components/dockercompose/billing_platform_service/docker-compose.yml @@ -14,8 +14,8 @@ services: environment: DISABLE_AUTH: true PROMETHEUS_PORT: 2112 - BILLING_SERVER_PORT: 2222 - CREDIT_RESERVATION_SERVER_PORT: 2223 + BILLING_SERVER_PORT: ${BILLING_SERVER_PORT:-2222} + CREDIT_RESERVATION_SERVER_PORT: ${CREDIT_RESERVATION_SERVER_PORT:-2223} WORKFLOW_OWNERSHIP_PROOF_SERVER_HOST: 0.0.0.0 MAINNET_WORKFLOW_REGISTRY_CHAIN_SELECTOR: ${MAINNET_WORKFLOW_REGISTRY_CHAIN_SELECTOR:-} TESTNET_WORKFLOW_REGISTRY_CHAIN_SELECTOR: ${MAINNET_WORKFLOW_REGISTRY_CHAIN_SELECTOR:-} From f3fb81642a3ea7e0a4ffb0049cc56413a74ac653 Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Thu, 11 Sep 2025 10:57:32 -0600 Subject: [PATCH 5/8] fix env var name mismatch --- .../billing_platform_service/billing_platform_service.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/framework/components/dockercompose/billing_platform_service/billing_platform_service.go b/framework/components/dockercompose/billing_platform_service/billing_platform_service.go index 685cc9c2b..6960052af 100644 --- a/framework/components/dockercompose/billing_platform_service/billing_platform_service.go +++ b/framework/components/dockercompose/billing_platform_service/billing_platform_service.go @@ -111,8 +111,8 @@ func New(in *Input) (*Output, error) { // set development defaults for necessary environment variables and allow them to be overridden by the host process envVars := make(map[string]string) - envVars["BILLING_SERVICE_PORT"] = DEFAULT_BILLING_PLATFORM_SERVICE_BILLING_GRPC_PORT - envVars["CREDIT_RESERVATION_SERVICE_PORT"] = DEFAULT_BILLING_PLATFORM_SERVICE_CREDIT_GRPC_PORT + envVars["BILLING_SERVER_PORT"] = DEFAULT_BILLING_PLATFORM_SERVICE_BILLING_GRPC_PORT + envVars["CREDIT_RESERVATION_SERVER_PORT"] = DEFAULT_BILLING_PLATFORM_SERVICE_CREDIT_GRPC_PORT envVars["MAINNET_WORKFLOW_REGISTRY_CHAIN_SELECTOR"] = strconv.FormatUint(in.ChainSelector, 10) envVars["MAINNET_WORKFLOW_REGISTRY_CONTRACT_ADDRESS"] = in.WorkflowRegistryAddress envVars["MAINNET_WORKFLOW_REGISTRY_RPC_URL"] = in.RPCURL @@ -247,8 +247,8 @@ func New(in *Input) (*Output, error) { func getExternalPorts(ctx context.Context, billingExternalHost string, envVars map[string]string, billingContainer *testcontainers.DockerContainer) (*BillingPlatformServiceOutput, error) { ports := map[string]nat.Port{ - "billing": nat.Port(envVars["BILLING_SERVICE_PORT"]), - "credit": nat.Port(envVars["CREDIT_RESERVATION_SERVICE_PORT"]), + "billing": nat.Port(envVars["BILLING_SERVER_PORT"]), + "credit": nat.Port(envVars["CREDIT_RESERVATION_SERVER_PORT"]), } output := BillingPlatformServiceOutput{} From 01df7c1d991eb6894fb71f7b515cdefcc4f07f47 Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Thu, 11 Sep 2025 11:45:01 -0600 Subject: [PATCH 6/8] one more env var ref fix --- .../billing_platform_service/billing_platform_service.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/components/dockercompose/billing_platform_service/billing_platform_service.go b/framework/components/dockercompose/billing_platform_service/billing_platform_service.go index 6960052af..4fbbb468a 100644 --- a/framework/components/dockercompose/billing_platform_service/billing_platform_service.go +++ b/framework/components/dockercompose/billing_platform_service/billing_platform_service.go @@ -159,8 +159,8 @@ func New(in *Input) (*Output, error) { stack.WaitForService(DEFAULT_BILLING_PLATFORM_SERVICE_SERVICE_NAME, wait.ForAll( wait.ForLog("GRPC server is live").WithPollInterval(200*time.Millisecond), - wait.ForListeningPort(nat.Port(envVars["BILLING_SERVICE_PORT"])), - wait.ForListeningPort(nat.Port(envVars["CREDIT_RESERVATION_SERVICE_PORT"])), + wait.ForListeningPort(nat.Port(envVars["BILLING_SERVER_PORT"])), + wait.ForListeningPort(nat.Port(envVars["CREDIT_RESERVATION_SERVER_PORT"])), ).WithDeadline(1*time.Minute), ) From 5779ddad6f81aee136562f7d1a77ef3d7e677a39 Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Thu, 11 Sep 2025 12:14:16 -0600 Subject: [PATCH 7/8] static ports --- .../billing_platform_service.go | 10 ++++------ .../billing_platform_service/docker-compose.yml | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/framework/components/dockercompose/billing_platform_service/billing_platform_service.go b/framework/components/dockercompose/billing_platform_service/billing_platform_service.go index 4fbbb468a..9222e910a 100644 --- a/framework/components/dockercompose/billing_platform_service/billing_platform_service.go +++ b/framework/components/dockercompose/billing_platform_service/billing_platform_service.go @@ -111,8 +111,6 @@ func New(in *Input) (*Output, error) { // set development defaults for necessary environment variables and allow them to be overridden by the host process envVars := make(map[string]string) - envVars["BILLING_SERVER_PORT"] = DEFAULT_BILLING_PLATFORM_SERVICE_BILLING_GRPC_PORT - envVars["CREDIT_RESERVATION_SERVER_PORT"] = DEFAULT_BILLING_PLATFORM_SERVICE_CREDIT_GRPC_PORT envVars["MAINNET_WORKFLOW_REGISTRY_CHAIN_SELECTOR"] = strconv.FormatUint(in.ChainSelector, 10) envVars["MAINNET_WORKFLOW_REGISTRY_CONTRACT_ADDRESS"] = in.WorkflowRegistryAddress envVars["MAINNET_WORKFLOW_REGISTRY_RPC_URL"] = in.RPCURL @@ -159,8 +157,8 @@ func New(in *Input) (*Output, error) { stack.WaitForService(DEFAULT_BILLING_PLATFORM_SERVICE_SERVICE_NAME, wait.ForAll( wait.ForLog("GRPC server is live").WithPollInterval(200*time.Millisecond), - wait.ForListeningPort(nat.Port(envVars["BILLING_SERVER_PORT"])), - wait.ForListeningPort(nat.Port(envVars["CREDIT_RESERVATION_SERVER_PORT"])), + wait.ForListeningPort(nat.Port(DEFAULT_BILLING_PLATFORM_SERVICE_BILLING_GRPC_PORT)), + wait.ForListeningPort(nat.Port(DEFAULT_BILLING_PLATFORM_SERVICE_CREDIT_GRPC_PORT)), ).WithDeadline(1*time.Minute), ) @@ -247,8 +245,8 @@ func New(in *Input) (*Output, error) { func getExternalPorts(ctx context.Context, billingExternalHost string, envVars map[string]string, billingContainer *testcontainers.DockerContainer) (*BillingPlatformServiceOutput, error) { ports := map[string]nat.Port{ - "billing": nat.Port(envVars["BILLING_SERVER_PORT"]), - "credit": nat.Port(envVars["CREDIT_RESERVATION_SERVER_PORT"]), + "billing": DEFAULT_BILLING_PLATFORM_SERVICE_BILLING_GRPC_PORT, + "credit": DEFAULT_BILLING_PLATFORM_SERVICE_CREDIT_GRPC_PORT, } output := BillingPlatformServiceOutput{} diff --git a/framework/components/dockercompose/billing_platform_service/docker-compose.yml b/framework/components/dockercompose/billing_platform_service/docker-compose.yml index df7c3b27c..b0294c800 100644 --- a/framework/components/dockercompose/billing_platform_service/docker-compose.yml +++ b/framework/components/dockercompose/billing_platform_service/docker-compose.yml @@ -14,8 +14,8 @@ services: environment: DISABLE_AUTH: true PROMETHEUS_PORT: 2112 - BILLING_SERVER_PORT: ${BILLING_SERVER_PORT:-2222} - CREDIT_RESERVATION_SERVER_PORT: ${CREDIT_RESERVATION_SERVER_PORT:-2223} + BILLING_SERVER_PORT: 2222 + CREDIT_RESERVATION_SERVER_PORT: 2223 WORKFLOW_OWNERSHIP_PROOF_SERVER_HOST: 0.0.0.0 MAINNET_WORKFLOW_REGISTRY_CHAIN_SELECTOR: ${MAINNET_WORKFLOW_REGISTRY_CHAIN_SELECTOR:-} TESTNET_WORKFLOW_REGISTRY_CHAIN_SELECTOR: ${MAINNET_WORKFLOW_REGISTRY_CHAIN_SELECTOR:-} From fe68fdc199b515bab041ec9edb81c985912bc057 Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Thu, 11 Sep 2025 14:40:04 -0600 Subject: [PATCH 8/8] clean up --- .../billing_platform_service/billing_platform_service.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/components/dockercompose/billing_platform_service/billing_platform_service.go b/framework/components/dockercompose/billing_platform_service/billing_platform_service.go index 9222e910a..0c23d8a46 100644 --- a/framework/components/dockercompose/billing_platform_service/billing_platform_service.go +++ b/framework/components/dockercompose/billing_platform_service/billing_platform_service.go @@ -221,7 +221,7 @@ func New(in *Input) (*Output, error) { } // get mapped ports for billing platform service - serviceOutput, err := getExternalPorts(ctx, billingExternalHost, envVars, billingContainer) + serviceOutput, err := getExternalPorts(ctx, billingExternalHost, billingContainer) if err != nil { return nil, errors.Wrap(err, "failed to get mapped port for Billing Platform Service") } @@ -243,7 +243,7 @@ func New(in *Input) (*Output, error) { return output, nil } -func getExternalPorts(ctx context.Context, billingExternalHost string, envVars map[string]string, billingContainer *testcontainers.DockerContainer) (*BillingPlatformServiceOutput, error) { +func getExternalPorts(ctx context.Context, billingExternalHost string, billingContainer *testcontainers.DockerContainer) (*BillingPlatformServiceOutput, error) { ports := map[string]nat.Port{ "billing": DEFAULT_BILLING_PLATFORM_SERVICE_BILLING_GRPC_PORT, "credit": DEFAULT_BILLING_PLATFORM_SERVICE_CREDIT_GRPC_PORT,