Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion pkg/cloud/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ package cloud
import (
"fmt"
"io"
"strings"
"sync"

"google.golang.org/grpc"
"google.golang.org/grpc/reflection"

"github.com/nitrictech/cli/pkg/cloud/apis"
"github.com/nitrictech/cli/pkg/cloud/batch"
"github.com/nitrictech/cli/pkg/cloud/env"
"github.com/nitrictech/cli/pkg/cloud/gateway"
"github.com/nitrictech/cli/pkg/cloud/http"
"github.com/nitrictech/cli/pkg/cloud/keyvalue"
Expand Down Expand Up @@ -255,6 +257,18 @@ type LocalCloudOptions struct {
}

func New(projectName string, opts LocalCloudOptions) (*LocalCloud, error) {
hostname := env.NITRIC_HOSTNAME.String()

// Reject hostnames containing characters that would produce malformed URLs
if strings.ContainsAny(hostname, "/?#\r\n \t") {
return nil, fmt.Errorf("NITRIC_HOSTNAME contains invalid characters: %q", hostname)
}

// Bracket IPv6 literals for use in URLs (RFC 3986)
if strings.Contains(hostname, ":") && !strings.HasPrefix(hostname, "[") {
hostname = "[" + hostname + "]"
}

localTopics, err := topics.NewLocalTopicsService()
if err != nil {
return nil, err
Expand All @@ -268,6 +282,7 @@ func New(projectName string, opts LocalCloudOptions) (*LocalCloud, error) {
localStorage, err := storage.NewLocalStorageService(storage.StorageOptions{
AccessKey: "dummykey",
SecretKey: "dummysecret",
Hostname: hostname,
})
if err != nil {
return nil, err
Expand All @@ -283,6 +298,7 @@ func New(projectName string, opts LocalCloudOptions) (*LocalCloud, error) {
LogWriter: opts.LogWriter,
LocalConfig: opts.LocalConfig,
BatchPlugin: localBatch,
Hostname: hostname,
})
if err != nil {
return nil, err
Expand All @@ -309,6 +325,9 @@ func New(projectName string, opts LocalCloudOptions) (*LocalCloud, error) {
return nil, err
}

// connectionStringHost controls how application services reach the Postgres container,
// which is distinct from NITRIC_HOSTNAME (how callers reach the Nitric backend).
// Postgres is its own container with host-mapped ports, so it needs separate addressing.
connectionStringHost := "localhost"

// Use the host.docker.internal address for connection strings with local cloud run mode
Expand All @@ -321,7 +340,7 @@ func New(projectName string, opts LocalCloudOptions) (*LocalCloud, error) {
return nil, err
}

localWebsites := websites.NewLocalWebsitesService(localGateway.GetApiAddress, localGateway.GetWebsocketAddress, opts.LocalCloudMode == StartMode)
localWebsites := websites.NewLocalWebsitesService(localGateway.GetApiAddress, localGateway.GetWebsocketAddress, opts.LocalCloudMode == StartMode, hostname)

return &LocalCloud{
servers: make(map[string]*server.NitricServer),
Expand Down
4 changes: 4 additions & 0 deletions pkg/cloud/env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,7 @@ var (
)

var MAX_WORKERS = env.GetEnv("MAX_WORKERS", "300")

// The hostname that the local Nitric backend is reachable at.
// Override when the backend runs in a container and callers address it by container name/IP.
var NITRIC_HOSTNAME = env.GetEnv("NITRIC_HOSTNAME", "localhost")
16 changes: 12 additions & 4 deletions pkg/cloud/gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ type LocalGatewayService struct {
serviceListener net.Listener

localConfig localconfig.LocalConfiguration
hostname string

logWriter io.Writer

Expand All @@ -114,7 +115,7 @@ var _ gateway.GatewayService = &LocalGatewayService{}
// GetTriggerAddress - Returns the base address built-in nitric services, like schedules and topics, will be exposed on.
func (s *LocalGatewayService) GetTriggerAddress() string {
if s.serviceListener != nil {
return strings.Replace(s.serviceListener.Addr().String(), "[::]", "localhost", 1)
return strings.Replace(s.serviceListener.Addr().String(), "[::]", s.hostname, 1)
}

return ""
Expand All @@ -134,7 +135,7 @@ func (s *LocalGatewayService) GetApiAddresses() map[string]string {
protocol = "https"
}

address := strings.Replace(srv.lis.Addr().String(), "[::]", "localhost", 1)
address := strings.Replace(srv.lis.Addr().String(), "[::]", s.hostname, 1)

addresses[srv.name] = fmt.Sprintf("%s://%s", protocol, address)
}
Expand Down Expand Up @@ -182,7 +183,7 @@ func (s *LocalGatewayService) GetHttpWorkerAddresses() map[string]string {
protocol = "https"
}

address := strings.Replace(srv.lis.Addr().String(), "[::]", "localhost", 1)
address := strings.Replace(srv.lis.Addr().String(), "[::]", s.hostname, 1)

addresses[srv.name] = fmt.Sprintf("%s://%s", protocol, address)
}
Expand All @@ -199,7 +200,7 @@ func (s *LocalGatewayService) GetWebsocketAddresses() map[string]string {

for socket, srv := range s.socketServer {
if srv.workerCount > 0 {
srvAddress := strings.Replace(srv.lis.Addr().String(), "[::]", "localhost", 1)
srvAddress := strings.Replace(srv.lis.Addr().String(), "[::]", s.hostname, 1)
addresses[socket] = srvAddress
}
}
Expand Down Expand Up @@ -932,16 +933,23 @@ type NewGatewayOpts struct {
LogWriter io.Writer
LocalConfig localconfig.LocalConfiguration
BatchPlugin *batch.LocalBatchService
Hostname string
}

// Create new HTTP gateway
// XXX: No External Args for function atm (currently the plugin loader does not pass any argument information)
func NewGateway(opts NewGatewayOpts) (*LocalGatewayService, error) {
hostname := opts.Hostname
if hostname == "" {
hostname = "localhost"
}

return &LocalGatewayService{
ApiTlsCredentials: opts.TLSCredentials,
bus: EventBus.New(),
logWriter: opts.LogWriter,
localConfig: opts.LocalConfig,
batchPlugin: opts.BatchPlugin,
hostname: hostname,
}, nil
}
14 changes: 12 additions & 2 deletions pkg/cloud/storage/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ type LocalStorageService struct {
listeners State

storageListener net.Listener
hostname string

bus EventBus.Bus
}
Expand Down Expand Up @@ -472,11 +473,13 @@ func (r *LocalStorageService) PreSignUrl(ctx context.Context, req *storagepb.Sto

// XXX: Do not URL encode keys (path needs to be preserved)
// TODO: May need to re-write slashes to a non-escapable character format
port := r.storageListener.Addr().(*net.TCPAddr).Port

switch req.Operation {
case storagepb.StoragePreSignUrlRequest_WRITE:
address = fmt.Sprintf("http://localhost:%d/write/%s", r.storageListener.Addr().(*net.TCPAddr).Port, tokenString)
address = fmt.Sprintf("http://%s:%d/write/%s", r.hostname, port, tokenString)
case storagepb.StoragePreSignUrlRequest_READ:
address = fmt.Sprintf("http://localhost:%d/read/%s", r.storageListener.Addr().(*net.TCPAddr).Port, tokenString)
address = fmt.Sprintf("http://%s:%d/read/%s", r.hostname, port, tokenString)
}

if address == "" {
Expand All @@ -491,6 +494,7 @@ func (r *LocalStorageService) PreSignUrl(ctx context.Context, req *storagepb.Sto
type StorageOptions struct {
AccessKey string
SecretKey string
Hostname string
}

func corsMiddleware(next http.Handler) http.Handler {
Expand All @@ -511,8 +515,14 @@ func corsMiddleware(next http.Handler) http.Handler {
func NewLocalStorageService(opts StorageOptions) (*LocalStorageService, error) {
var err error

hostname := opts.Hostname
if hostname == "" {
hostname = "localhost"
}

storageService := &LocalStorageService{
listeners: map[string]map[string]int{},
hostname: hostname,
bus: EventBus.New(),
}

Expand Down
10 changes: 8 additions & 2 deletions pkg/cloud/websites/websites.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ type LocalWebsiteService struct {
getApiAddress GetApiAddress
getWebsocketAddress GetApiAddress
isStartCmd bool
hostname string

bus EventBus.Bus
}
Expand Down Expand Up @@ -99,7 +100,7 @@ func (l *LocalWebsiteService) register(website Website, port int) {
defer l.websiteRegLock.Unlock()

// Emulates the CDN URL used in a deployed environment
publicUrl := fmt.Sprintf("http://localhost:%d/%s", port, strings.TrimPrefix(website.BasePath, "/"))
publicUrl := fmt.Sprintf("http://%s:%d/%s", l.hostname, port, strings.TrimPrefix(website.BasePath, "/"))

l.state[website.Name] = Website{
WebsitePb: website.WebsitePb,
Expand Down Expand Up @@ -397,12 +398,17 @@ func (l *LocalWebsiteService) Start(websites []Website) error {
return nil
}

func NewLocalWebsitesService(getApiAddress GetApiAddress, getWebsocketAddress GetApiAddress, isStartCmd bool) *LocalWebsiteService {
func NewLocalWebsitesService(getApiAddress GetApiAddress, getWebsocketAddress GetApiAddress, isStartCmd bool, hostname string) *LocalWebsiteService {
if hostname == "" {
hostname = "localhost"
}

return &LocalWebsiteService{
state: State{},
bus: EventBus.New(),
getApiAddress: getApiAddress,
getWebsocketAddress: getWebsocketAddress,
isStartCmd: isStartCmd,
hostname: hostname,
}
}