Skip to content

Commit

Permalink
[RFC0028] Support for Cloud Native Buildpacks lifecycle (#2871)
Browse files Browse the repository at this point in the history
Co-authored-by: Johannes Dillmann <j.dillmann@sap.com>
Co-authored-by: Nicolas Bender <nicolas.bender@sap.com>
Co-authored-by: Pavel Busko <pavel.busko@sap.com>
Co-authored-by: Ralf Pannemans <ralf.pannemans@sap.com>
Co-authored-by: Al Berez <al.berez@broadcom.com>
Co-authored-by: João Pereira <joaopapereira@gmail.com>
  • Loading branch information
7 people authored Sep 23, 2024
1 parent 301073b commit 0cc96f4
Show file tree
Hide file tree
Showing 37 changed files with 857 additions and 222 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/tests-integration-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ jobs:
"include_container_networking": true,
"include_detect": true,
"include_docker": true,
"include_cnb": true,
"include_internet_dependent": true,
"include_isolation_segments": true,
"isolation_segment_name": "persistent_isolation_segment",
Expand Down Expand Up @@ -237,6 +238,7 @@ jobs:
cf api ${API} --skip-ssl-validation
cf auth
cf enable-feature-flag diego_docker
cf enable-feature-flag diego_cnb
cf enable-feature-flag service_instance_sharing
- name: Run CATS Tests
Expand Down
1 change: 1 addition & 0 deletions actor/v7action/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ func (actor Actor) CreateApplicationInSpace(app resources.Application, spaceGUID
LifecycleBuildpacks: app.LifecycleBuildpacks,
StackName: app.StackName,
Name: app.Name,
Credentials: app.Credentials,
SpaceGUID: spaceGUID,
})

Expand Down
3 changes: 3 additions & 0 deletions actor/v7pushaction/actor.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ func NewActor(v3Actor V7Actor, sharedActor SharedActor) *Actor {

HandleInstancesOverride,
HandleStartCommandOverride,
HandleCNBCredentialsOverride,

HandleLifecycleOverride,

// Type must come before endpoint because endpoint validates against type
HandleHealthCheckTypeOverride,
Expand Down
12 changes: 12 additions & 0 deletions actor/v7pushaction/create_push_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ func (actor Actor) CreatePushPlans(
BitsPath: manifestApplication.Path,
}

if manifestApplication.Lifecycle != "" {
plan.Application.LifecycleType = manifestApplication.Lifecycle
}

if overrides.Lifecycle != "" {
plan.Application.LifecycleType = overrides.Lifecycle
}

if overrides.CNBCredentials != nil {
plan.Application.Credentials = overrides.CNBCredentials
}

if manifestApplication.Docker != nil {
plan.DockerImageCredentials = v7action.DockerImageCredentials{
Path: manifestApplication.Docker.Image,
Expand Down
22 changes: 21 additions & 1 deletion actor/v7pushaction/create_push_plans_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,17 @@ var _ = Describe("CreatePushPlans", func() {

manifest = manifestparser.Manifest{
Applications: []manifestparser.Application{
{Name: "name-1", Path: "path1"},
{Name: "name-1", Path: "path1", Lifecycle: "cnb"},
{Name: "name-2", Path: "path2", Docker: &manifestparser.Docker{Image: "image", Username: "uname"}},
},
}
orgGUID = "org"
spaceGUID = "space"
flagOverrides = FlagOverrides{
DockerPassword: "passwd",
CNBCredentials: map[string]interface{}{
"foo": "bar",
},
}

testUpdatePlanCount = 0
Expand Down Expand Up @@ -120,6 +123,10 @@ var _ = Describe("CreatePushPlans", func() {
Expect(pushPlans[0].DockerImageCredentials.Username).To(Equal(""))
Expect(pushPlans[0].DockerImageCredentials.Password).To(Equal(""))
Expect(pushPlans[0].BitsPath).To(Equal("path1"))
Expect(pushPlans[0].Application.LifecycleType).To(BeEquivalentTo("cnb"))
Expect(pushPlans[0].Application.Credentials).To(Equal(map[string]interface{}{
"foo": "bar",
}))
Expect(pushPlans[1].Application.Name).To(Equal("name-2"))
Expect(pushPlans[1].Application.GUID).To(Equal("app-guid-2"))
Expect(pushPlans[1].SpaceGUID).To(Equal(spaceGUID))
Expand All @@ -128,7 +135,20 @@ var _ = Describe("CreatePushPlans", func() {
Expect(pushPlans[1].DockerImageCredentials.Username).To(Equal("uname"))
Expect(pushPlans[1].DockerImageCredentials.Password).To(Equal("passwd"))
Expect(pushPlans[1].BitsPath).To(Equal("path2"))
Expect(pushPlans[1].Application.LifecycleType).To(BeEquivalentTo(""))
})
})

When("lifecycle is overwritten", func() {
BeforeEach(func() {
flagOverrides = FlagOverrides{
Lifecycle: "buildpack",
}
})

It("uses the lifecycle from the command line", func() {
Expect(pushPlans[0].Application.LifecycleType).To(BeEquivalentTo("buildpack"))
})
})

})
23 changes: 23 additions & 0 deletions actor/v7pushaction/handle_cnb_credentials_override.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package v7pushaction

import (
"code.cloudfoundry.org/cli/command/translatableerror"
"code.cloudfoundry.org/cli/util/manifestparser"
)

func HandleCNBCredentialsOverride(manifest manifestparser.Manifest, overrides FlagOverrides) (manifestparser.Manifest, error) {
if overrides.CNBCredentials != nil {
if manifest.ContainsMultipleApps() {
return manifest, translatableerror.CommandLineArgsWithMultipleAppsError{}
}

app := manifest.GetFirstApp()
if app.RemainingManifestFields == nil {
app.RemainingManifestFields = map[string]interface{}{}
}

app.RemainingManifestFields["cnb-credentials"] = overrides.CNBCredentials
}

return manifest, nil
}
66 changes: 66 additions & 0 deletions actor/v7pushaction/handle_cnb_credentials_override_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package v7pushaction_test

import (
. "code.cloudfoundry.org/cli/actor/v7pushaction"
"code.cloudfoundry.org/cli/util/manifestparser"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("HandleCNBCredentialsOverride", func() {
var (
originalManifest manifestparser.Manifest
transformedManifest manifestparser.Manifest
overrides FlagOverrides
executeErr error
)

BeforeEach(func() {
originalManifest = manifestparser.Manifest{
Applications: []manifestparser.Application{{}},
}
overrides = FlagOverrides{}
})

JustBeforeEach(func() {
transformedManifest, executeErr = HandleCNBCredentialsOverride(originalManifest, overrides)
})

When("the cnb credentials are present", func() {
BeforeEach(func() {
overrides.CNBCredentials = map[string]interface{}{
"foo": "bar",
}
})

It("add it to the raw manifest", func() {
Expect(executeErr).NotTo(HaveOccurred())
Expect(transformedManifest).To(Equal(manifestparser.Manifest{
Applications: []manifestparser.Application{{
RemainingManifestFields: map[string]interface{}{
"cnb-credentials": map[string]interface{}{
"foo": "bar",
},
},
}},
}))
})

})

When("the credentials are not present", func() {
BeforeEach(func() {
overrides.CNBCredentials = nil
})

It("does not add it to the raw manifest", func() {
Expect(executeErr).NotTo(HaveOccurred())
Expect(transformedManifest).To(Equal(manifestparser.Manifest{
Applications: []manifestparser.Application{{}},
}))

})

})
})
19 changes: 19 additions & 0 deletions actor/v7pushaction/handle_lifecycle_override.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package v7pushaction

import (
"code.cloudfoundry.org/cli/command/translatableerror"
"code.cloudfoundry.org/cli/util/manifestparser"
)

func HandleLifecycleOverride(manifest manifestparser.Manifest, overrides FlagOverrides) (manifestparser.Manifest, error) {
if overrides.Lifecycle != "" {
if manifest.ContainsMultipleApps() {
return manifest, translatableerror.CommandLineArgsWithMultipleAppsError{}
}

app := manifest.GetFirstApp()
app.Lifecycle = overrides.Lifecycle
}

return manifest, nil
}
2 changes: 2 additions & 0 deletions actor/v7pushaction/push_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type FlagOverrides struct {
DockerImage string
DockerPassword string
DockerUsername string
CNBCredentials map[string]interface{}
HealthCheckEndpoint string
HealthCheckTimeout int64
HealthCheckType constant.HealthCheckType
Expand All @@ -62,6 +63,7 @@ type FlagOverrides struct {
NoManifest bool
Task bool
LogRateLimit string
Lifecycle constant.AppLifecycleType
}

func (state PushPlan) String() string {
Expand Down
11 changes: 11 additions & 0 deletions api/cloudcontroller/ccv3/application_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,17 @@ var _ = Describe("Application", func() {
})
})

When("lifecycle type cnb is provided", func() {
BeforeEach(func() {
app.LifecycleType = constant.AppLifecycleTypeCNB
app.LifecycleBuildpacks = []string{"docker://nodejs"}
})

It("sets the lifecycle buildpack to be empty in the JSON", func() {
Expect(string(appBytes)).To(MatchJSON(`{"lifecycle":{"data":{"buildpacks":["docker://nodejs"]},"type":"cnb"}}`))
})
})

When("null buildpack is provided", func() {
BeforeEach(func() {
app.LifecycleBuildpacks = []string{"null"}
Expand Down
3 changes: 3 additions & 0 deletions api/cloudcontroller/ccv3/constant/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ const (
// AppLifecycleTypeDocker will pull a docker image from a registry to run an
// app.
AppLifecycleTypeDocker AppLifecycleType = "docker"
// AppLifecycleTypeCNB will use a droplet (created with cloud native buildpacks)
// and a rootfs to run the app.
AppLifecycleTypeCNB AppLifecycleType = "cnb"
)

// ApplicationAction represents the action being taken on an application
Expand Down
2 changes: 1 addition & 1 deletion cf/commands/application/apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"code.cloudfoundry.org/cli/cf/flags"
. "code.cloudfoundry.org/cli/cf/i18n"
"code.cloudfoundry.org/cli/cf/models"
"code.cloudfoundry.org/cli/plugin/models"
plugin_models "code.cloudfoundry.org/cli/plugin/models"

"code.cloudfoundry.org/cli/cf/api"
"code.cloudfoundry.org/cli/cf/configuration/coreconfig"
Expand Down
Loading

0 comments on commit 0cc96f4

Please sign in to comment.