Skip to content

Commit

Permalink
Refactoring after review
Browse files Browse the repository at this point in the history
1. Assign TokenFile property
2. Added fallback for npm commands
3. Remove temp droplet file after the tests
  • Loading branch information
EugeneTitarchuk authored and arjun024 committed May 9, 2022
1 parent c85dbcd commit 33dd371
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 28 deletions.
91 changes: 67 additions & 24 deletions src/nodejs/hooks/sealights.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@ package hooks
import (
"encoding/json"
"fmt"
"github.com/cloudfoundry/libbuildpack"
"io"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"

"github.com/cloudfoundry/libbuildpack"
)

const EmptyTokenError = "token cannot be empty (env SL_TOKEN | SL_TOKEN_FILE)"
const CommandStringError = "Cannot find command begin term"
const NpmCommandStringError = "NPM command without package.json file is not supported"
const SealightsNotBoundError = "Sealights service not bound"
const EmptyBuildError = "build session id cannot be empty (env SL_BUILD_SESSION_ID | SL_BUILD_SESSION_ID_FILE)"
const Procfile = "Procfile"
Expand Down Expand Up @@ -84,12 +88,8 @@ func (sl *SealightsHook) AfterCompile(stager *libbuildpack.Stager) error {
}

func (sl *SealightsHook) RunWithSealights() bool {
_, token := sl.GetTokenFromEnvironment()
if token == "" {
return false
} else {
return true
}
isTokenFound, _, _ := sl.GetTokenFromEnvironment()
return isTokenFound
}

func (sl *SealightsHook) SetApplicationStartInProcfile(stager *libbuildpack.Stager) error {
Expand All @@ -99,9 +99,16 @@ func (sl *SealightsHook) SetApplicationStartInProcfile(stager *libbuildpack.Stag
return err
}

originalStartCommand := string(bytes)
_, usePackageJson := sl.usePackageJson(originalStartCommand, stager)
if usePackageJson {
// move to package json scenario
return sl.SetApplicationStartInPackageJson(stager)
}

// we suppose that format is "web: node <application>"
var newCmd string
err, newCmd = sl.updateStartCommand(string(bytes))
err, newCmd = sl.updateStartCommand(originalStartCommand)

if err != nil {
return err
Expand All @@ -122,9 +129,31 @@ func (sl *SealightsHook) SetApplicationStartInProcfile(stager *libbuildpack.Stag
return nil
}

func (sl *SealightsHook) getSealightsOptions(app string, token string) *SealightsOptions {
func (sl *SealightsHook) usePackageJson(originalStartCommand string, stager *libbuildpack.Stager) (error, bool) {

isNpmCommand, err := regexp.MatchString(`(^(web:\s)?cd[^&]*\s&&\snpm)|(^(web:\s)?npm)`, originalStartCommand)
if err != nil {
return err, false
}

isPackageExists := fileExists(filepath.Join(stager.BuildDir(), PackageJsonFile))
if !isNpmCommand {
return err, false
}

if isNpmCommand && isPackageExists {
// move to package json scenario
return nil, true
}

// case with npm command without package.json is not supported
return fmt.Errorf(NpmCommandStringError), false
}

func (sl *SealightsHook) getSealightsOptions(app string, token string, tokenFile string) *SealightsOptions {
o := &SealightsOptions{
Token: token,
TokenFile: tokenFile,
BsId: os.Getenv("SL_BUILD_SESSION_ID"),
BsIdFile: os.Getenv("SL_BUILD_SESSION_ID_FILE"),
Proxy: os.Getenv("SL_PROXY"),
Expand Down Expand Up @@ -184,11 +213,17 @@ func (sl *SealightsHook) SetApplicationStartInManifest(stager *libbuildpack.Stag
if err != nil {
return err
}
originalCommand := m.Applications[0].Command
originalStartCommand := m.Applications[0].Command

_, usePackageJson := sl.usePackageJson(originalStartCommand, stager)
if usePackageJson {
// move to package json scenario
return sl.SetApplicationStartInPackageJson(stager)
}

// we suppose that format is "start: node <application>"
var newCmd string
err, newCmd = sl.updateStartCommand(originalCommand)
err, newCmd = sl.updateStartCommand(originalStartCommand)
if err != nil {
return err
}
Expand All @@ -204,20 +239,19 @@ func (sl *SealightsHook) SetApplicationStartInManifest(stager *libbuildpack.Stag
}

func (sl *SealightsHook) updateStartCommand(originalCommand string) (error, string) {
slFound, token := sl.GetTokenFromEnvironment()
slTokenFound, token, tokenFile := sl.GetTokenFromEnvironment()

if !slFound {
if !slTokenFound {
sl.Log.Info("Sealights service not found")
return fmt.Errorf(SealightsNotBoundError), ""
}

if token == "" {
sl.Log.Info("Sealights token not found")
return fmt.Errorf(EmptyTokenError), ""
}
split := strings.SplitAfter(originalCommand, "node")
split := strings.SplitAfterN(originalCommand, "node", 2)

o := sl.getSealightsOptions(split[1], token)
if len(split) < 2 {
return fmt.Errorf(CommandStringError), ""
}
o := sl.getSealightsOptions(split[1], token, tokenFile)

err := sl.validate(o)
if err != nil {
Expand Down Expand Up @@ -332,7 +366,7 @@ func containsSealightsService(key string, services interface{}, query string) bo
return false
}

func (sl *SealightsHook) GetTokenFromEnvironment() (bool, string) {
func (sl *SealightsHook) GetTokenFromEnvironment() (bool, string, string) {

type rawVcapServicesJSONValue map[string]interface{}

Expand All @@ -342,13 +376,13 @@ func (sl *SealightsHook) GetTokenFromEnvironment() (bool, string) {

if vcapServicesEnvironment == "" {
sl.Log.Debug("Sealights could not find VCAP_SERVICES in the environment")
return false, ""
return false, "", ""
}

err := json.Unmarshal([]byte(vcapServicesEnvironment), &vcapServices)
if err != nil {
sl.Log.Warning("Sealights could not parse VCAP_SERVICES")
return false, ""
return false, "", ""
}

for key, services := range vcapServices {
Expand All @@ -359,10 +393,19 @@ func (sl *SealightsHook) GetTokenFromEnvironment() (bool, string) {
service := val[serviceIndex].(map[string]interface{})
if credentials, exists := service["credentials"].(map[string]interface{}); exists {
token := getContrastCredentialString(credentials, "token")
return true, token
tokenFile := getContrastCredentialString(credentials, "tokenFile")
if token == "" && tokenFile == "" {
return false, "", ""
}
return true, token, tokenFile
}
}
}
}
return false, ""
return false, "", ""
}

func fileExists(path string) bool {
_, err := os.Stat(path)
return !os.IsNotExist(err)
}
18 changes: 14 additions & 4 deletions src/nodejs/integration/nodejs_app_with_sealights_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"archive/tar"
"compress/gzip"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
Expand All @@ -21,6 +22,7 @@ var _ = Describe("CF NodeJS Buildpack", func() {
app *cutlass.App
serviceBrokerApp *cutlass.App
serviceNameOne string
files []string
expected = strings.ReplaceAll("./node_modules/.bin/slnodejs run --useinitialcolor true --token token1 --buildsessionid bs1 ./dist/server.js", " ", "")
)

Expand All @@ -34,6 +36,11 @@ var _ = Describe("CF NodeJS Buildpack", func() {
_ = RunCF("delete-service", "-f", serviceNameOne)

serviceBrokerApp = DestroyApp(serviceBrokerApp)

for _, file := range files {
err := os.Remove(file)
Expect(err).NotTo(HaveOccurred())
}
})

It("deploying a NodeJS app with sealights", func() {
Expand All @@ -49,11 +56,14 @@ var _ = Describe("CF NodeJS Buildpack", func() {
"token": "token1"
}`)).To(Succeed())

PushAppAndConfirm(app)
Expect(app.PushNoStart()).To(Succeed())
Expect(RunCF("bind-service", app.Name, serviceNameOne)).To(Succeed())
PushAppAndConfirm(app)
Expect(app.DownloadDroplet(filepath.Join(app.Path, "droplet.tgz"))).To(Succeed())
file, err := os.Open(filepath.Join(app.Path, "droplet.tgz"))
Expect(app.Restart()).To(Succeed())

tmpDropletFile := filepath.Join(os.TempDir(), fmt.Sprintf("droplet-%s.tgz", cutlass.RandStringRunes(10)))
files = append(files, tmpDropletFile)
Expect(app.DownloadDroplet(tmpDropletFile)).To(Succeed())
file, err := os.Open(tmpDropletFile)
Expect(err).ToNot(HaveOccurred())
defer file.Close()
gz, err := gzip.NewReader(file)
Expand Down

0 comments on commit 33dd371

Please sign in to comment.