Skip to content

Commit

Permalink
Implement the spec reconcileName in BuildWorkload
Browse files Browse the repository at this point in the history
 - Add a test for config.LoadFromPath
 - Add a config option for reconciler name
 - Add reconcilerName to spec in BuildWorkload
 - Make kpack-image-builder create an image only when the reconciler
   name matches

Co-authored-by: Dave Walter <[email protected]>
  • Loading branch information
Clint Yoshimura and davewalter committed Jul 26, 2022
1 parent c5de457 commit 52d628b
Show file tree
Hide file tree
Showing 13 changed files with 151 additions and 17 deletions.
2 changes: 1 addition & 1 deletion .envrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export KUBEBUILDER_ASSETS=$PWD/testbin/bin
source <(setup-envtest use -p env --bin-dir "$PWD/testbin")
export APICONFIG=$PWD/config/base/apiconfig/
export CONTROLLERSCONFIG=$PWD/config/base/controllersconfig/
2 changes: 2 additions & 0 deletions controllers/api/v1alpha1/buildworkload_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ type BuildWorkloadSpec struct {
Env []v1.EnvVar `json:"env,omitempty"`

Services []v1.ObjectReference `json:"services,omitempty"`

ReconcilerName string `json:"reconcilerName"`
}

// BuildWorkloadStatus defines the observed state of BuildWorkload
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
buildReconciler: kpack-image-builder
cfProcessDefaults:
memoryMB: 1024
diskQuotaMB: 1024
Expand All @@ -7,4 +8,4 @@ packageRegistrySecretName: image-registry-credentials # Create this secret in th
# with no spaces, e.g. 5d12h45m. Default is 30 days
taskTTL: 30d
workloads_tls_secret_name: korifi-workloads-ingress-cert
workloads_tls_secret_namespace: korifi-controllers-system
workloads_tls_secret_namespace: korifi-controllers-system
1 change: 1 addition & 0 deletions controllers/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type ControllerConfig struct {
TaskTTL string `yaml:"taskTTL"`
WorkloadsTLSSecretName string `yaml:"workloads_tls_secret_name"`
WorkloadsTLSSecretNamespace string `yaml:"workloads_tls_secret_namespace"`
BuildReconciler string `yaml:"buildReconciler"`
}

type CFProcessDefaults struct {
Expand Down
87 changes: 87 additions & 0 deletions controllers/config/config_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,100 @@
package config_test

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

"gopkg.in/yaml.v3"

"code.cloudfoundry.org/korifi/controllers/config"

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

var _ = Describe("LoadFromPath", func() {
var (
configPath string
retConfig *config.ControllerConfig
retErr error
)

BeforeEach(func() {
// Setup filesystem
var err error
configPath, err = os.MkdirTemp("", "config")
Expect(err).NotTo(HaveOccurred())

config := config.ControllerConfig{
CFProcessDefaults: config.CFProcessDefaults{
MemoryMB: 1024,
DiskQuotaMB: 512,
},
CFRootNamespace: "rootNamespace",
PackageRegistrySecretName: "packageRegistrySecretName",
TaskTTL: "taskTTL",
WorkloadsTLSSecretName: "workloadsTLSSecretName",
WorkloadsTLSSecretNamespace: "workloadsTLSSecretNamespace",
BuildReconciler: "buildReconciler",
}
configYAML, err := yaml.Marshal(config)
Expect(err).NotTo(HaveOccurred())

err = os.WriteFile(filepath.Join(configPath, "file1"), configYAML, 0o644)
Expect(err).NotTo(HaveOccurred())

err = os.WriteFile(filepath.Join(configPath, "file2"), []byte(`buildReconciler: "newBuildReconciler"`), 0o644)
Expect(err).NotTo(HaveOccurred())
})

AfterEach(func() {
Expect(os.RemoveAll(configPath)).To(Succeed())
})

JustBeforeEach(func() {
retConfig, retErr = config.LoadFromPath(configPath)
})

It("loads the configuration from all the files in the given directory", func() {
Expect(retErr).NotTo(HaveOccurred())
Expect(*retConfig).To(Equal(config.ControllerConfig{
CFProcessDefaults: config.CFProcessDefaults{
MemoryMB: 1024,
DiskQuotaMB: 512,
},
CFRootNamespace: "rootNamespace",
PackageRegistrySecretName: "packageRegistrySecretName",
TaskTTL: "taskTTL",
WorkloadsTLSSecretName: "workloadsTLSSecretName",
WorkloadsTLSSecretNamespace: "workloadsTLSSecretNamespace",
BuildReconciler: "newBuildReconciler",
}))
})

When("the path does not exist", func() {
BeforeEach(func() {
configPath = "notarealpath"
})

It("throws an error", func() {
Expect(retErr).To(MatchError(fmt.Sprintf("error reading config dir %q: open %s: no such file or directory", configPath, configPath)))
})
})

When("a file cannot be read", func() {
BeforeEach(func() {
err := os.WriteFile(filepath.Join(configPath, "file3"), []byte(`buildReconciler: "newBuildReconciler"`), 0o000)
Expect(err).NotTo(HaveOccurred())
})

It("throws an error", func() {
Expect(retErr).To(MatchError(fmt.Sprintf("failed to open file: open %s: permission denied", filepath.Join(configPath, "file3"))))
})
})
})

var _ = Describe("ParseTaskTTL", func() {
var (
taskTTLString string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ spec:
- name
type: object
type: array
reconcilerName:
type: string
services:
items:
description: 'ObjectReference contains enough information to let
Expand Down Expand Up @@ -248,6 +250,7 @@ spec:
type: object
required:
- buildRef
- reconcilerName
type: object
status:
description: BuildWorkloadStatus defines the observed state of BuildWorkload
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
buildReconciler: kpack-image-builder
cfProcessDefaults:
memoryMB: 1024
diskQuotaMB: 1024
cfRootNamespace: cf
packageRegistrySecretName: image-registry-credentials # Create this secret in the rootNamespace
taskTTL: 5s
workloads_tls_secret_name: korifi-workloads-ingress-cert
workloads_tls_secret_namespace: korifi-controllers-system
workloads_tls_secret_namespace: korifi-controllers-system
1 change: 1 addition & 0 deletions controllers/config/samples/build_workload.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ spec:
image: gcr.io/cf-relint-greengrass/cf-crd-staging-spike/packages/665a78f8-ed97-47e6-85b2-60cbcc21d5e2
imagePullSecrets:
- name: image-registry-credentials
reconcilerName: kpack-image-builder
1 change: 1 addition & 0 deletions controllers/controllers/workloads/cfbuild_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ func (r *CFBuildReconciler) createBuildWorkloadAndUpdateStatus(ctx context.Conte
ImagePullSecrets: cfPackage.Spec.Source.Registry.ImagePullSecrets,
},
},
ReconcilerName: r.ControllerConfig.BuildReconciler,
},
}

Expand Down
12 changes: 11 additions & 1 deletion controllers/controllers/workloads/cfbuild_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ var _ = Describe("CFBuildReconciler", func() {
fakeClient,
scheme.Scheme,
zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)),
&config.ControllerConfig{},
&config.ControllerConfig{
BuildReconciler: "myCustomBuildReconciler",
},
fakeEnvBuilder,
)
req = ctrl.Request{
Expand Down Expand Up @@ -170,6 +172,14 @@ var _ = Describe("CFBuildReconciler", func() {

Expect(actualWorkload.Spec.Env).To(Equal(buildEnv))
})

It("sets the build reconciler from the controller config", func() {
Expect(fakeClient.CreateCallCount()).To(Equal(1), "fakeClient Create was not called 1 time")
_, obj, _ := fakeClient.CreateArgsForCall(0)
actualWorkload, ok := obj.(*korifiv1alpha1.BuildWorkload)
Expect(ok).To(BeTrue(), "create wasn't passed a buildWorkload")
Expect(actualWorkload.Spec.ReconcilerName).To(Equal("myCustomBuildReconciler"))
})
})

When("on unhappy path", func() {
Expand Down
5 changes: 5 additions & 0 deletions kpack-image-builder/controllers/buildworkload_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const (
clusterBuilderAPIVersion = "kpack.io/v1alpha2"
kpackServiceAccount = "kpack-service-account"
BuildWorkloadLabelKey = "korifi.cloudfoundry.org/build-workload-name"
kpackReconcilerName = "kpack-image-builder"
)

//counterfeiter:generate -o fake -fake-name RegistryAuthFetcher . RegistryAuthFetcher
Expand Down Expand Up @@ -202,6 +203,10 @@ func (r *BuildWorkloadReconciler) ensureKpackImageRequirements(ctx context.Conte
}

func (r *BuildWorkloadReconciler) createKpackImageAndUpdateStatus(ctx context.Context, buildWorkload *korifiv1alpha1.BuildWorkload) error {
if buildWorkload.Spec.ReconcilerName != kpackReconcilerName {
// Stop reconciling since the buildWorkload.Spec.ReconcilerName does not match this builder
return nil
}
serviceAccountName := kpackServiceAccount
kpackImageTag := path.Join(r.ControllerConfig.KpackImageTag, buildWorkload.Name)
kpackImageName := buildWorkload.Name
Expand Down
46 changes: 33 additions & 13 deletions kpack-image-builder/controllers/buildworkload_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package controllers_test
import (
"context"
"encoding/base64"
"fmt"
"time"

korifiv1alpha1 "code.cloudfoundry.org/korifi/controllers/api/v1alpha1"
Expand All @@ -25,16 +26,18 @@ var _ = Describe("BuildWorkloadReconciler", func() {
succeededConditionType = "Succeeded"
kpackReadyConditionType = "Ready"
wellFormedRegistryCredentialsSecret = "image-registry-credentials"
kpackReconcilerName = "kpack-image-builder"
)

var (
namespaceGUID string
cfBuildGUID string
namespace *corev1.Namespace
buildWorkload *korifiv1alpha1.BuildWorkload
source korifiv1alpha1.PackageSource
env []corev1.EnvVar
services []corev1.ObjectReference
namespaceGUID string
cfBuildGUID string
namespace *corev1.Namespace
buildWorkload *korifiv1alpha1.BuildWorkload
source korifiv1alpha1.PackageSource
env []corev1.EnvVar
services []corev1.ObjectReference
reconcilerName string
)

eventuallyKpackImageShould := func(assertion func(*buildv1alpha2.Image, Gomega)) {
Expand Down Expand Up @@ -86,6 +89,8 @@ var _ = Describe("BuildWorkloadReconciler", func() {
ImagePullSecrets: []corev1.LocalObjectReference{{Name: wellFormedRegistryCredentialsSecret}},
},
}

reconcilerName = kpackReconcilerName
})

AfterEach(func() {
Expand All @@ -94,7 +99,7 @@ var _ = Describe("BuildWorkloadReconciler", func() {

When("BuildWorkload is first created", func() {
JustBeforeEach(func() {
buildWorkload = BuildWorkloadObject(cfBuildGUID, namespaceGUID, source, env, services)
buildWorkload = BuildWorkloadObject(cfBuildGUID, namespaceGUID, source, env, services, reconcilerName)
Expect(k8sClient.Create(context.Background(), buildWorkload)).To(Succeed())
})

Expand Down Expand Up @@ -174,13 +179,27 @@ var _ = Describe("BuildWorkloadReconciler", func() {
}).Should(BeTrue())
})
})

When("The build workload reconciler name is not kpack-image-builder", func() {
BeforeEach(func() {
reconcilerName = "notkpackreconciler"
})

It("does not create a kpack image resource", func() {
Consistently(func(g Gomega) {
kpackImage := new(buildv1alpha2.Image)
err := k8sClient.Get(context.Background(), types.NamespacedName{Name: cfBuildGUID, Namespace: namespaceGUID}, kpackImage)
g.Expect(err).To(MatchError(fmt.Sprintf("images.kpack.io %q not found", cfBuildGUID)))
}).Should(Succeed())
})
})
})

When("the kpack Image was already created", func() {
var createdKpackImage *buildv1alpha2.Image

BeforeEach(func() {
buildWorkload = BuildWorkloadObject(cfBuildGUID, namespaceGUID, source, env, services)
buildWorkload = BuildWorkloadObject(cfBuildGUID, namespaceGUID, source, env, services, reconcilerName)
Expect(k8sClient.Create(context.Background(), buildWorkload)).To(Succeed())

kpackImageLookupKey := types.NamespacedName{Name: cfBuildGUID, Namespace: namespaceGUID}
Expand Down Expand Up @@ -308,7 +327,7 @@ func PrefixedGUID(prefix string) string {
return prefix + "-" + uuid.NewString()[:8]
}

func BuildWorkloadObject(cfBuildGUID string, namespace string, source korifiv1alpha1.PackageSource, env []corev1.EnvVar, services []corev1.ObjectReference) *korifiv1alpha1.BuildWorkload {
func BuildWorkloadObject(cfBuildGUID string, namespace string, source korifiv1alpha1.PackageSource, env []corev1.EnvVar, services []corev1.ObjectReference, reconcilerName string) *korifiv1alpha1.BuildWorkload {
return &korifiv1alpha1.BuildWorkload{
ObjectMeta: metav1.ObjectMeta{
Name: cfBuildGUID,
Expand All @@ -318,9 +337,10 @@ func BuildWorkloadObject(cfBuildGUID string, namespace string, source korifiv1al
BuildRef: corev1.LocalObjectReference{
Name: cfBuildGUID,
},
Source: source,
Env: env,
Services: services,
Source: source,
Env: env,
Services: services,
ReconcilerName: reconcilerName,
},
}
}
Expand Down
2 changes: 2 additions & 0 deletions kpack-image-builder/controllers/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ func TestAPIs(t *testing.T) {

SetDefaultEventuallyTimeout(10 * time.Second)
SetDefaultEventuallyPollingInterval(200 * time.Millisecond)
SetDefaultConsistentlyDuration(10 * time.Second)
SetDefaultConsistentlyPollingInterval(200 * time.Millisecond)

RunSpecs(t, "Controller Suite")
}
Expand Down

0 comments on commit 52d628b

Please sign in to comment.