Skip to content

Commit

Permalink
Add BPL_DEBUG_ENABLED to set --inspect
Browse files Browse the repository at this point in the history
Signed-off-by: Ralf Pannemans <[email protected]>
Signed-off-by: Pavel Busko <[email protected]>
Co-authored-by: Ralf Pannemans <[email protected]>
  • Loading branch information
c0d1ngm0nk3y committed Nov 10, 2023
1 parent be44298 commit a311946
Show file tree
Hide file tree
Showing 21 changed files with 292 additions and 43 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,17 @@ the `BP_NODE_PROJECT_PATH` environment variable at build time either directly
file](https://github.com/buildpacks/spec/blob/main/extensions/project-descriptor.md).
This could be useful if your app is a part of a monorepo.

### Enabling Inspector for Remote Debugging

To enable the Inspector set the `BPL_DEBUG_ENABLED` environment variable at launch time. Optionally, you can specify the `BPL_DEBUG_PORT` environment variable to use a specific port.

```shell
$BPL_DEBUG_ENABLED="true"
$BPL_DEBUG_PORT="9009"
```

For more information on debugging, see [Official Documentation](https://nodejs.org/en/docs/guides/debugging-getting-started)

## Run Tests

To run all unit tests, run:
Expand Down
9 changes: 6 additions & 3 deletions build.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import (
"strconv"
"time"

"github.com/paketo-buildpacks/libnodejs"
"github.com/paketo-buildpacks/packit/v2"
"github.com/paketo-buildpacks/packit/v2/cargo"
"github.com/paketo-buildpacks/packit/v2/chronos"
"github.com/paketo-buildpacks/packit/v2/postal"
"github.com/paketo-buildpacks/packit/v2/sbom"
"github.com/paketo-buildpacks/packit/v2/scribe"
"github.com/paketo-buildpacks/libnodejs"
)

//go:generate faux --interface EntryResolver --output fakes/entry_resolver.go
Expand Down Expand Up @@ -191,8 +191,10 @@ func Build(entryResolver EntryResolver, dependencyManager DependencyManager, sbo
}

logger.EnvironmentVariables(nodeLayer)

nodeLayer.ExecD = []string{filepath.Join(context.CNBPath, "bin", "optimize-memory")}
nodeLayer.ExecD = []string{
filepath.Join(context.CNBPath, "bin", "optimize-memory"),
filepath.Join(context.CNBPath, "bin", "inspector"),
}

logger.Subprocess("Writing exec.d/0-optimize-memory")
logger.Action("Calculates available memory based on container limits at launch time.")
Expand All @@ -201,6 +203,7 @@ func Build(entryResolver EntryResolver, dependencyManager DependencyManager, sbo
logger.Action("Assigns the NODE_OPTIONS environment variable with flag setting to optimize memory.")
logger.Action("Limits the total size of all objects on the heap to 75%% of the MEMORY_AVAILABLE.")
}
logger.Subprocess("Writing exec.d/1-inspector")
logger.Break()

return packit.BuildResult{
Expand Down
4 changes: 4 additions & 0 deletions build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
}))
Expect(layer.ExecD).To(Equal([]string{
filepath.Join(cnbDir, "bin", "optimize-memory"),
filepath.Join(cnbDir, "bin", "inspector"),
}))

Expect(layer.Metadata).To(Equal(map[string]interface{}{
Expand Down Expand Up @@ -238,6 +239,7 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
Expect(buffer.String()).To(ContainSubstring(" Made available in the MEMORY_AVAILABLE environment variable."))
Expect(buffer.String()).NotTo(ContainSubstring(" Assigns the NODE_OPTIONS environment variable with flag setting to optimize memory."))
Expect(buffer.String()).NotTo(ContainSubstring(" Limits the total size of all objects on the heap to 75% of the MEMORY_AVAILABLE."))
Expect(buffer.String()).To(ContainSubstring(" Writing exec.d/1-inspector"))
})

context("when the os environment contains a directive to optimize memory", func() {
Expand Down Expand Up @@ -471,6 +473,7 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
}))
Expect(layer.ExecD).To(Equal([]string{
filepath.Join(cnbDir, "bin", "optimize-memory"),
filepath.Join(cnbDir, "bin", "inspector"),
}))

Expect(layer.Metadata).To(Equal(map[string]interface{}{
Expand All @@ -488,6 +491,7 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
Expect(buffer.String()).To(ContainSubstring(" Made available in the MEMORY_AVAILABLE environment variable."))
Expect(buffer.String()).NotTo(ContainSubstring(" Assigns the NODE_OPTIONS environment variable with flag setting to optimize memory."))
Expect(buffer.String()).NotTo(ContainSubstring(" Limits the total size of all objects on the heap to 75% of the MEMORY_AVAILABLE."))
Expect(buffer.String()).To(ContainSubstring(" Writing exec.d/1-inspector"))
})
})

Expand Down
2 changes: 1 addition & 1 deletion buildpack.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ api = "0.7"
uri = "https://github.com/paketo-buildpacks/node-engine/blob/main/LICENSE"

[metadata]
include-files = ["bin/build", "bin/detect", "bin/run", "bin/optimize-memory", "buildpack.toml"]
include-files = ["bin/build", "bin/detect", "bin/run", "bin/optimize-memory", "bin/inspector", "buildpack.toml"]
pre-package = "./scripts/build.sh"
[metadata.default-versions]
node = "20.*.*"
Expand Down
14 changes: 14 additions & 0 deletions cmd/inspector/internal/init_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package internal_test

import (
"testing"

"github.com/sclevine/spec"
"github.com/sclevine/spec/report"
)

func TestUnitInspector(t *testing.T) {
suite := spec.New("cmd/inspector/internal", spec.Report(report.Terminal{}))
suite("Run", testRun)
suite.Run(t)
}
31 changes: 31 additions & 0 deletions cmd/inspector/internal/run.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package internal

import (
"fmt"
"io"
"strings"

"github.com/BurntSushi/toml"
)

func Run(environment map[string]string, output io.Writer, root string) error {
variables := map[string]string{}
if debug, ok := environment["BPL_DEBUG_ENABLED"]; ok && debug == "true" {
option := "--inspect"
if debugPort, ok := environment["BPL_DEBUG_PORT"]; ok {
option = fmt.Sprintf("%s=127.0.0.1:%s", option, debugPort)
}

if nodeOpts, ok := environment["NODE_OPTIONS"]; ok {
if strings.Contains(nodeOpts, "--inspect") {
return nil
}

option = strings.Join([]string{nodeOpts, option}, " ")
}

variables["NODE_OPTIONS"] = option
}

return toml.NewEncoder(output).Encode(variables)
}
92 changes: 92 additions & 0 deletions cmd/inspector/internal/run_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package internal_test

import (
"bytes"
"os"
"testing"

"github.com/paketo-buildpacks/node-engine/cmd/inspector/internal"
"github.com/sclevine/spec"

. "github.com/onsi/gomega"
. "github.com/paketo-buildpacks/packit/v2/matchers"
)

func testRun(t *testing.T, context spec.G, it spec.S) {
var (
Expect = NewWithT(t).Expect

environment map[string]string
root string
)

it.Before(func() {
environment = map[string]string{}
})

it.After(func() {
Expect(os.RemoveAll(root)).To(Succeed())
})

context("when $BPL_DEBUG_ENABLE is set", func() {
it.Before(func() {
environment["BPL_DEBUG_ENABLED"] = "true"
})

it("--inspect is added to NODE_OPTIONS", func() {
environment["NODE_OPTIONS"] = "--existing"
buffer := bytes.NewBuffer(nil)

err := internal.Run(environment, buffer, root)
Expect(err).NotTo(HaveOccurred())

Expect(buffer.String()).To(MatchTOML(`
NODE_OPTIONS = "--existing --inspect"
`))
})

context("when $BPL_DEBUG_PORT is set", func() {
it.Before(func() {
environment["BPL_DEBUG_PORT"] = "1111"
})

it("sets the inspector port", func() {
buffer := bytes.NewBuffer(nil)

err := internal.Run(environment, buffer, root)
Expect(err).NotTo(HaveOccurred())

Expect(buffer.String()).To(MatchTOML(`
NODE_OPTIONS = "--inspect=127.0.0.1:1111"
`))
})
})

context("when $NODE_OPTIONS contains --inspect flag", func() {
it.Before(func() {
environment["NODE_OPTIONS"] = "--inspect=0.0.0.0:8888"
})

it("does not change it", func() {
buffer := bytes.NewBuffer(nil)

err := internal.Run(environment, buffer, root)
Expect(err).NotTo(HaveOccurred())

Expect(buffer.String()).To(BeEmpty())
})
})
})

context("when $BPL_DEBUG_ENABLED is not set", func() {
it("NODE_OPTIONS are not changed", func() {
environment["NODE_OPTIONS"] = "--existing"

buffer := bytes.NewBuffer(nil)
err := internal.Run(environment, buffer, root)
Expect(err).NotTo(HaveOccurred())
Expect(buffer.String()).To(BeEmpty())
})
})

}
16 changes: 16 additions & 0 deletions cmd/inspector/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package main

import (
"log"
"os"

"github.com/paketo-buildpacks/node-engine/cmd/inspector/internal"
"github.com/paketo-buildpacks/node-engine/cmd/util"
)

func main() {
err := internal.Run(util.LoadEnvironmentMap(os.Environ()), os.NewFile(3, "/dev/fd/3"), "/")
if err != nil {
log.Fatal(err)
}
}
1 change: 0 additions & 1 deletion cmd/optimize-memory/internal/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

func TestUnitOptimizeMemory(t *testing.T) {
suite := spec.New("cmd/optimize-memory/internal", spec.Report(report.Terminal{}))
suite("EnvironmentMap", testEnvironmentMap)
suite("Run", testRun)
suite.Run(t)
}
3 changes: 2 additions & 1 deletion cmd/optimize-memory/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import (
"os"

"github.com/paketo-buildpacks/node-engine/cmd/optimize-memory/internal"
"github.com/paketo-buildpacks/node-engine/cmd/util"
)

func main() {
err := internal.Run(internal.LoadEnvironmentMap(os.Environ()), os.NewFile(3, "/dev/fd/3"), "/")
err := internal.Run(util.LoadEnvironmentMap(os.Environ()), os.NewFile(3, "/dev/fd/3"), "/")
if err != nil {
log.Fatal(err)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package util

import "strings"

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package internal_test
package util_test

import (
"testing"

"github.com/paketo-buildpacks/node-engine/cmd/optimize-memory/internal"
"github.com/paketo-buildpacks/node-engine/cmd/util"
"github.com/sclevine/spec"

. "github.com/onsi/gomega"
Expand All @@ -13,7 +13,7 @@ func testEnvironmentMap(t *testing.T, context spec.G, it spec.S) {
var Expect = NewWithT(t).Expect

it("loads the environment into a map", func() {
env := internal.LoadEnvironmentMap([]string{
env := util.LoadEnvironmentMap([]string{
"SOME_KEY=some-value",
"OTHER_KEY=other-value=extra-value",
})
Expand Down
14 changes: 14 additions & 0 deletions cmd/util/init_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package util_test

import (
"testing"

"github.com/sclevine/spec"
"github.com/sclevine/spec/report"
)

func TestUnitUtils(t *testing.T) {
suite := spec.New("cmd/util", spec.Report(report.Terminal{}))
suite("EnvironmentMap", testEnvironmentMap)
suite.Run(t)
}
1 change: 1 addition & 0 deletions integration/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ func TestIntegration(t *testing.T) {
suite := spec.New("Integration", spec.Report(report.Terminal{}), spec.Parallel())
suite("Offline", testOffline)
suite("OptimizeMemory", testOptimizeMemory)
suite("Inspector", testInspector)
suite("ProjectPath", testProjectPath)
suite("Provides", testProvides)
suite("ReusingLayerRebuild", testReusingLayerRebuild)
Expand Down
76 changes: 76 additions & 0 deletions integration/inspector_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package integration

import (
"fmt"
"os"
"path/filepath"
"testing"

"github.com/paketo-buildpacks/occam"
"github.com/sclevine/spec"

. "github.com/onsi/gomega"
. "github.com/paketo-buildpacks/occam/matchers"
)

func testInspector(t *testing.T, context spec.G, it spec.S) {
var (
Expect = NewWithT(t).Expect
Eventually = NewWithT(t).Eventually

docker occam.Docker
pack occam.Pack

image occam.Image
container occam.Container
name string
source string
)

it.Before(func() {
docker = occam.NewDocker()
pack = occam.NewPack()

var err error
name, err = occam.RandomName()
Expect(err).NotTo(HaveOccurred())
})

it.After(func() {
Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed())
Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed())
Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed())
Expect(os.RemoveAll(source)).To(Succeed())
})

it("sets --inspect if set with env variable BPL_DEBUG_ENABLED", func() {
var err error
source, err = occam.Source(filepath.Join("testdata", "simple_app"))
Expect(err).NotTo(HaveOccurred())

var logs fmt.Stringer
image, logs, err = pack.WithNoColor().Build.
WithPullPolicy("never").
WithBuildpacks(
settings.Buildpacks.NodeEngine.Online,
settings.Buildpacks.Processes.Online,
).
Execute(name, source)

Expect(err).NotTo(HaveOccurred())
Expect(logs).To(ContainLines(
" Writing exec.d/1-inspector",
))

container, err = docker.Container.Run.
WithMemory("128m").
WithPublish("8080").
WithEnv(map[string]string{"BPL_DEBUG_ENABLED": "true", "BPL_DEBUG_PORT": "9000", "NODE_OPTIONS": "--no-warnings"}).
Execute(image.ID)
Expect(err).NotTo(HaveOccurred())

Eventually(container).Should(BeAvailable())
Eventually(container).Should(Serve(ContainSubstring("NodeOptions: --no-warnings --inspect=127.0.0.1:9000")).OnPort(8080).WithEndpoint("/node-options"))

})
}
Loading

0 comments on commit a311946

Please sign in to comment.