diff --git a/depot/containerstore/containerstore.go b/depot/containerstore/containerstore.go index 09a1afc2..0d262411 100644 --- a/depot/containerstore/containerstore.go +++ b/depot/containerstore/containerstore.go @@ -87,6 +87,8 @@ type containerStore struct { enableUnproxiedPortMappings bool advertisePreferenceForInstanceAddress bool + serviceBindingRoot ServiceBindingRootImplementor + jsonMarshaller func(any) ([]byte, error) } @@ -110,6 +112,7 @@ func New( cellID string, enableUnproxiedPortMappings bool, advertisePreferenceForInstanceAddress bool, + serviceBindingRoot ServiceBindingRootImplementor, jsonMarshaller func(any) ([]byte, error), ) ContainerStore { return &containerStore{ @@ -134,6 +137,7 @@ func New( enableUnproxiedPortMappings: enableUnproxiedPortMappings, advertisePreferenceForInstanceAddress: advertisePreferenceForInstanceAddress, + serviceBindingRoot: serviceBindingRoot, jsonMarshaller: jsonMarshaller, } } @@ -170,6 +174,7 @@ func (cs *containerStore) Reserve(logger lager.Logger, traceID string, req *exec cs.cellID, cs.enableUnproxiedPortMappings, cs.advertisePreferenceForInstanceAddress, + cs.serviceBindingRoot, cs.jsonMarshaller, )) diff --git a/depot/containerstore/containerstore_test.go b/depot/containerstore/containerstore_test.go index fd4cf450..44dc7dca 100644 --- a/depot/containerstore/containerstore_test.go +++ b/depot/containerstore/containerstore_test.go @@ -71,10 +71,11 @@ var _ = Describe("Container Store", func() { logManager *containerstorefakes.FakeLogManager logStreamer *fake_log_streamer.FakeLogStreamer - clock *fakeclock.FakeClock - eventEmitter *eventfakes.FakeHub - metronClient *mfakes.FakeIngressClient - rootFSSizer *configurationfakes.FakeRootFSSizer + clock *fakeclock.FakeClock + eventEmitter *eventfakes.FakeHub + metronClient *mfakes.FakeIngressClient + rootFSSizer *configurationfakes.FakeRootFSSizer + serviceBindingRootHandler *containerstorefakes.FakeServiceBindingRootImplementor ) var containerState = func(guid string) func() executor.State { @@ -113,6 +114,7 @@ var _ = Describe("Container Store", func() { clock = fakeclock.NewFakeClock(time.Now()) eventEmitter = &eventfakes.FakeHub{} rootFSSizer = new(configurationfakes.FakeRootFSSizer) + serviceBindingRootHandler = &containerstorefakes.FakeServiceBindingRootImplementor{} credManager.RunnerReturns(ifrit.RunFunc(func(signals <-chan os.Signal, ready chan<- struct{}) error { close(ready) @@ -164,6 +166,7 @@ var _ = Describe("Container Store", func() { cellID, true, advertisePreferenceForInstanceAddress, + serviceBindingRootHandler, json.Marshal, ) @@ -378,6 +381,10 @@ var _ = Describe("Container Store", func() { {Name: "beep", Value: "booop"}, } + serviceBindingFiles := []executor.ServiceBindingFiles{ + {Name: "/redis/username", Value: "redis_username"}, + } + logGuid = "log-guid-foo" runInfo = executor.RunInfo{ RootFSPath: "/foo/bar", @@ -406,6 +413,7 @@ var _ = Describe("Container Store", func() { }, EnableContainerProxy: true, LogRateLimitBytesPerSecond: logRateUnlimitedBytesPerSecond, + ServiceBindingFiles: serviceBindingFiles, } runReq = &executor.RunRequest{ @@ -489,6 +497,7 @@ var _ = Describe("Container Store", func() { cellID, true, advertisePreferenceForInstanceAddress, + serviceBindingRootHandler, json.Marshal, ) }) @@ -645,6 +654,26 @@ var _ = Describe("Container Store", func() { Expect(containerSpec.Env).To(Equal(expectedEnv)) }) + It("creates container with service binding root", func() { + expectedMount := garden.BindMount{ + SrcPath: "/var/vcap/data/rep/shared/garden/service_binding_root", + DstPath: "/etc/cf-instance-binding", + Mode: garden.BindMountModeRO, + Origin: garden.BindMountOriginHost, + } + + dependencyManager.DownloadCachedDependenciesReturns(containerstore.BindMounts{ + GardenBindMounts: []garden.BindMount{expectedMount}, + }, nil) + + _, err := containerStore.Create(logger, "some-trace-id", containerGuid) + Expect(err).NotTo(HaveOccurred()) + + Expect(gardenClient.CreateCallCount()).To(Equal(1)) + containerSpec := gardenClient.CreateArgsForCall(0) + Expect(containerSpec.BindMounts).To(ContainElement(expectedMount)) + }) + It("sets the correct external and internal ip", func() { container, err := containerStore.Create(logger, "some-trace-id", containerGuid) Expect(err).NotTo(HaveOccurred()) @@ -713,6 +742,7 @@ var _ = Describe("Container Store", func() { cellID, true, advertisePreferenceForInstanceAddress, + serviceBindingRootHandler, json.Marshal, ) }) @@ -1254,6 +1284,7 @@ var _ = Describe("Container Store", func() { cellID, true, advertisePreferenceForInstanceAddress, + serviceBindingRootHandler, json.Marshal, ) @@ -1344,6 +1375,7 @@ var _ = Describe("Container Store", func() { cellID, false, advertisePreferenceForInstanceAddress, + serviceBindingRootHandler, json.Marshal, ) }) @@ -2493,6 +2525,7 @@ var _ = Describe("Container Store", func() { cellID, true, advertisePreferenceForInstanceAddress, + serviceBindingRootHandler, fm.Marshal, ) }) @@ -3066,6 +3099,7 @@ var _ = Describe("Container Store", func() { cellID, true, advertisePreferenceForInstanceAddress, + serviceBindingRootHandler, json.Marshal, ) diff --git a/depot/containerstore/containerstorefakes/fake_service_binding_root_handler.go b/depot/containerstore/containerstorefakes/fake_service_binding_root_handler.go new file mode 100644 index 00000000..b96c1a0d --- /dev/null +++ b/depot/containerstore/containerstorefakes/fake_service_binding_root_handler.go @@ -0,0 +1,197 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package containerstorefakes + +import ( + "sync" + + "code.cloudfoundry.org/executor" + "code.cloudfoundry.org/executor/depot/containerstore" + "code.cloudfoundry.org/garden" + lager "code.cloudfoundry.org/lager/v3" +) + +type FakeServiceBindingRootImplementor struct { + CreateDirStub func(lager.Logger, executor.Container) ([]garden.BindMount, error) + createDirMutex sync.RWMutex + createDirArgsForCall []struct { + arg1 lager.Logger + arg2 executor.Container + } + createDirReturns struct { + result1 []garden.BindMount + result2 error + } + createDirReturnsOnCall map[int]struct { + result1 []garden.BindMount + result2 error + } + RemoveDirStub func(lager.Logger, executor.Container) error + removeDirMutex sync.RWMutex + removeDirArgsForCall []struct { + arg1 lager.Logger + arg2 executor.Container + } + removeDirReturns struct { + result1 error + } + removeDirReturnsOnCall map[int]struct { + result1 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeServiceBindingRootImplementor) CreateDir(arg1 lager.Logger, arg2 executor.Container) ([]garden.BindMount, error) { + fake.createDirMutex.Lock() + ret, specificReturn := fake.createDirReturnsOnCall[len(fake.createDirArgsForCall)] + fake.createDirArgsForCall = append(fake.createDirArgsForCall, struct { + arg1 lager.Logger + arg2 executor.Container + }{arg1, arg2}) + stub := fake.CreateDirStub + fakeReturns := fake.createDirReturns + fake.recordInvocation("CreateDir", []interface{}{arg1, arg2}) + fake.createDirMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeServiceBindingRootImplementor) CreateDirCallCount() int { + fake.createDirMutex.RLock() + defer fake.createDirMutex.RUnlock() + return len(fake.createDirArgsForCall) +} + +func (fake *FakeServiceBindingRootImplementor) CreateDirCalls(stub func(lager.Logger, executor.Container) ([]garden.BindMount, error)) { + fake.createDirMutex.Lock() + defer fake.createDirMutex.Unlock() + fake.CreateDirStub = stub +} + +func (fake *FakeServiceBindingRootImplementor) CreateDirArgsForCall(i int) (lager.Logger, executor.Container) { + fake.createDirMutex.RLock() + defer fake.createDirMutex.RUnlock() + argsForCall := fake.createDirArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeServiceBindingRootImplementor) CreateDirReturns(result1 []garden.BindMount, result2 error) { + fake.createDirMutex.Lock() + defer fake.createDirMutex.Unlock() + fake.CreateDirStub = nil + fake.createDirReturns = struct { + result1 []garden.BindMount + result2 error + }{result1, result2} +} + +func (fake *FakeServiceBindingRootImplementor) CreateDirReturnsOnCall(i int, result1 []garden.BindMount, result2 error) { + fake.createDirMutex.Lock() + defer fake.createDirMutex.Unlock() + fake.CreateDirStub = nil + if fake.createDirReturnsOnCall == nil { + fake.createDirReturnsOnCall = make(map[int]struct { + result1 []garden.BindMount + result2 error + }) + } + fake.createDirReturnsOnCall[i] = struct { + result1 []garden.BindMount + result2 error + }{result1, result2} +} + +func (fake *FakeServiceBindingRootImplementor) RemoveDir(arg1 lager.Logger, arg2 executor.Container) error { + fake.removeDirMutex.Lock() + ret, specificReturn := fake.removeDirReturnsOnCall[len(fake.removeDirArgsForCall)] + fake.removeDirArgsForCall = append(fake.removeDirArgsForCall, struct { + arg1 lager.Logger + arg2 executor.Container + }{arg1, arg2}) + stub := fake.RemoveDirStub + fakeReturns := fake.removeDirReturns + fake.recordInvocation("RemoveDir", []interface{}{arg1, arg2}) + fake.removeDirMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeServiceBindingRootImplementor) RemoveDirCallCount() int { + fake.removeDirMutex.RLock() + defer fake.removeDirMutex.RUnlock() + return len(fake.removeDirArgsForCall) +} + +func (fake *FakeServiceBindingRootImplementor) RemoveDirCalls(stub func(lager.Logger, executor.Container) error) { + fake.removeDirMutex.Lock() + defer fake.removeDirMutex.Unlock() + fake.RemoveDirStub = stub +} + +func (fake *FakeServiceBindingRootImplementor) RemoveDirArgsForCall(i int) (lager.Logger, executor.Container) { + fake.removeDirMutex.RLock() + defer fake.removeDirMutex.RUnlock() + argsForCall := fake.removeDirArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeServiceBindingRootImplementor) RemoveDirReturns(result1 error) { + fake.removeDirMutex.Lock() + defer fake.removeDirMutex.Unlock() + fake.RemoveDirStub = nil + fake.removeDirReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeServiceBindingRootImplementor) RemoveDirReturnsOnCall(i int, result1 error) { + fake.removeDirMutex.Lock() + defer fake.removeDirMutex.Unlock() + fake.RemoveDirStub = nil + if fake.removeDirReturnsOnCall == nil { + fake.removeDirReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.removeDirReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeServiceBindingRootImplementor) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.createDirMutex.RLock() + defer fake.createDirMutex.RUnlock() + fake.removeDirMutex.RLock() + defer fake.removeDirMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeServiceBindingRootImplementor) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ containerstore.ServiceBindingRootImplementor = new(FakeServiceBindingRootImplementor) diff --git a/depot/containerstore/service_binding_root_handler.go b/depot/containerstore/service_binding_root_handler.go new file mode 100644 index 00000000..9ea047c6 --- /dev/null +++ b/depot/containerstore/service_binding_root_handler.go @@ -0,0 +1,132 @@ +package containerstore + +import ( + "fmt" + "os" + "path/filepath" + + "code.cloudfoundry.org/executor" + "code.cloudfoundry.org/garden" + "code.cloudfoundry.org/lager/v3" +) + +//go:generate counterfeiter -o containerstorefakes/fake_service_binding_root_handler.go . ServiceBindingRootImplementor +type ServiceBindingRootImplementor interface { + CreateDir(logger lager.Logger, container executor.Container) ([]garden.BindMount, error) + RemoveDir(logger lager.Logger, container executor.Container) error +} + +type ServiceBindingRootHandler struct { + containerMountPath string + bindingRootPath string +} + +func NewServiceBindingRootHandler( + bindingRoot string, + containerMountPath string, +) *ServiceBindingRootHandler { + return &ServiceBindingRootHandler{ + bindingRootPath: bindingRoot, + containerMountPath: containerMountPath, + } +} + +func (h *ServiceBindingRootHandler) CreateDir(logger lager.Logger, container executor.Container) ([]garden.BindMount, error) { + containerDir := filepath.Join(h.bindingRootPath, container.Guid) + err := os.Mkdir(containerDir, 0755) + if err != nil { + return nil, err + } + + logger.Info("creating-dir - service binding root") + + errServiceBinding := h.createBindingRootsForServices(logger, containerDir, container) + if errServiceBinding != nil { + logger.Error("creating-dir-service-binding-root-failed", errServiceBinding) + return nil, err + } + + return []garden.BindMount{ + { + SrcPath: containerDir, + DstPath: h.containerMountPath, + Mode: garden.BindMountModeRO, + Origin: garden.BindMountOriginHost, + }, + }, nil +} + +func (h *ServiceBindingRootHandler) createBindingRootsForServices( + logger lager.Logger, + containerDir string, + containers executor.Container, +) error { + var cleanupFiles []*os.File + + for _, roots := range containers.RunInfo.ServiceBindingFiles { + dirName := filepath.Dir(roots.Name) + if dirName == "" { + err := fmt.Errorf("failed to extract service bindig directory. format is: /serviceName/fileName") + logger.Error("service binding directory is required", err, lager.Data{"dirName": "is empty"}) + + continue + } + + fileName := filepath.Base(roots.Name) + if fileName == "" { + err := fmt.Errorf("failed to extract service config file. format is: /serviceName/fileName") + logger.Error("service config file is required", err, lager.Data{"fileName": "is empty"}) + + continue + } + + dirName = filepath.Join(containerDir, dirName) + + err := os.Mkdir(dirName, 0755) + if err != nil { + logger.Error("failed-to-create-directory", err, lager.Data{"dirName": dirName}) + return fmt.Errorf("failed to create directory %s: %w", dirName, err) + } + + filePath := filepath.Join(dirName, fileName) + + serviceFile, err := os.Create(filePath) + if err != nil { + logger.Error("failed-to-create-file", err, lager.Data{"filePath": filePath}) + return fmt.Errorf("failed to create file %s: %w", filePath, err) + } + + cleanupFiles = append(cleanupFiles, serviceFile) + + err = os.WriteFile(filePath, []byte(roots.Value), 0644) + if err != nil { + logger.Error("failed-to-write-to-file", err, lager.Data{"filePath": filePath}) + err := serviceFile.Close() + if err != nil { + return err + } + return fmt.Errorf("failed to write to file %s: %w", filePath, err) + } + } + + for _, file := range cleanupFiles { + err := file.Close() + if err != nil { + logger.Error("failed-to-close-file", err, lager.Data{"filePath": file.Name()}) + return fmt.Errorf("failed to close file %s: %w", file.Name(), err) + } + } + + return nil +} + +func (h *ServiceBindingRootHandler) RemoveDir(logger lager.Logger, container executor.Container) error { + path := filepath.Join(h.bindingRootPath, container.Guid) + + err := os.RemoveAll(path) + if err != nil { + logger.Error("failed-to-remove-service-binding-root-directory", err, lager.Data{"directory": path}) + } + + return err +} diff --git a/depot/containerstore/service_binding_root_handler_test.go b/depot/containerstore/service_binding_root_handler_test.go new file mode 100644 index 00000000..0a386300 --- /dev/null +++ b/depot/containerstore/service_binding_root_handler_test.go @@ -0,0 +1,103 @@ +package containerstore_test + +import ( + "os" + "path/filepath" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "code.cloudfoundry.org/executor" + "code.cloudfoundry.org/executor/depot/containerstore" + "code.cloudfoundry.org/garden" +) + +var _ = Describe("Service Binding Root Handler", func() { + var ( + tmpdir string + fakeContainerUUID string + + handler *containerstore.ServiceBindingRootHandler + container executor.Container + ) + + AfterEach(func() { + os.RemoveAll(tmpdir) + }) + + BeforeEach(func() { + fakeContainerUUID = "E62613F8-7E85-4F49-B3EF-690BD2AE7EF2" + + container = executor.Container{Guid: fakeContainerUUID} + + var serviceBindingFiles []executor.ServiceBindingFiles + container.ServiceBindingFiles = append(serviceBindingFiles, executor.ServiceBindingFiles{ + Name: "/redis/username", Value: "username", + }) + + tmpdir = filepath.Join(os.TempDir(), "service_binding_root_handler") + err := os.MkdirAll(tmpdir, os.ModePerm) + Expect(err).NotTo(HaveOccurred()) + + handler = containerstore.NewServiceBindingRootHandler( + tmpdir, + fakeContainerUUID, + ) + }) + + Context("CreateDir", func() { + It("returns a valid bind mount", func() { + mount, err := handler.CreateDir(logger, container) + Expect(err).To(Succeed()) + + Expect(mount).To(HaveLen(1)) + Expect(mount[0].SrcPath).To(BeADirectory()) + Expect(mount[0].DstPath).To(Equal(fakeContainerUUID)) + Expect(mount[0].Mode).To(Equal(garden.BindMountModeRO)) + Expect(mount[0].Origin).To(Equal(garden.BindMountOriginHost)) + }) + + It("returns a valid service configuration directory", func() { + _, err := handler.CreateDir(logger, container) + Expect(err).To(Succeed()) + + Expect(filepath.Join(tmpdir, fakeContainerUUID, "redis")).To(BeADirectory()) + Expect(filepath.Join(tmpdir, fakeContainerUUID, "redis", "username")).To(BeAnExistingFile()) + Expect(filepath.Join(tmpdir, fakeContainerUUID, "redis", "username")).To(BeARegularFile()) + }) + + It("validates the content of the username file", func() { + _, err := handler.CreateDir(logger, container) + Expect(err).To(Succeed()) + + usernameFilePath := filepath.Join(tmpdir, fakeContainerUUID, "redis", "username") + Expect(usernameFilePath).To(BeAnExistingFile()) + + content, err := os.ReadFile(usernameFilePath) + Expect(err).NotTo(HaveOccurred()) + Expect(string(content)).To(Equal("username")) + }) + + It("removes service binding root directory", func() { + err := handler.RemoveDir(logger, container) + Expect(err).NotTo(HaveOccurred()) + + serviceBindingRootPath := filepath.Join(tmpdir, fakeContainerUUID) + Eventually(serviceBindingRootPath).ShouldNot(BeADirectory()) + }) + + Context("when making directory fails", func() { + BeforeEach(func() { + handler = containerstore.NewServiceBindingRootHandler( + "/some/fake/path", + "mount_path", + ) + }) + + It("returns an error", func() { + _, err := handler.CreateDir(logger, executor.Container{Guid: "fake_guid"}) + Expect(err).To(HaveOccurred()) + }) + }) + }) +}) diff --git a/depot/containerstore/storenode.go b/depot/containerstore/storenode.go index 4aec2552..bdb4bf83 100644 --- a/depot/containerstore/storenode.go +++ b/depot/containerstore/storenode.go @@ -33,6 +33,7 @@ const ContainerMissingMessage = "missing garden container" const VolmanMountFailed = "failed to mount volume" const BindMountCleanupFailed = "failed to cleanup bindmount artifacts" const CredDirFailed = "failed to create credentials directory" +const ServiceBindingRootFailed = "failed to create service binding root" const ContainerCompletedCount = "ContainerCompletedCount" const ContainerExitedOnTimeoutCount = "ContainerExitedOnTimeoutCount" @@ -92,6 +93,8 @@ type storeNode struct { startTime time.Time regenerateCertsCh chan struct{} + serviceBindingRoot ServiceBindingRootImplementor + jsonMarshaller func(any) ([]byte, error) } @@ -116,6 +119,7 @@ func newStoreNode( cellID string, enableUnproxiedPortMappings bool, advertisePreferenceForInstanceAddress bool, + serviceBindingRoot ServiceBindingRootImplementor, jsonMarshaller func(any) ([]byte, error), ) *storeNode { return &storeNode{ @@ -143,6 +147,7 @@ func newStoreNode( enableUnproxiedPortMappings: enableUnproxiedPortMappings, advertisePreferenceForInstanceAddress: advertisePreferenceForInstanceAddress, regenerateCertsCh: make(chan struct{}, 1), + serviceBindingRoot: serviceBindingRoot, jsonMarshaller: jsonMarshaller, } } @@ -242,7 +247,19 @@ func (n *storeNode) Create(logger lager.Logger, traceID string) error { n.complete(logger, traceID, true, CredDirFailed, true) return err } + + if len(n.info.ServiceBindingFiles) > 0 { + serviceBindingRoot, err := n.serviceBindingRoot.CreateDir(logger, info) + if err != nil { + n.complete(logger, traceID, true, ServiceBindingRootFailed, true) + return err + } + + n.bindMounts = append(n.bindMounts, serviceBindingRoot...) + } + n.bindMounts = append(n.bindMounts, credMounts...) + info.Env = append(info.Env, envs...) if n.useDeclarativeHealthCheck { @@ -745,6 +762,7 @@ func (n *storeNode) Destroy(logger lager.Logger, traceID string) error { // ensure these directories are removed even if the container fails to destroy defer n.removeCredsDir(logger, info) defer n.umountVolumeMounts(logger, info) + defer n.removeServiceBindingRoot(logger, info) err := n.destroyContainer(logger, traceID) if err != nil { @@ -849,6 +867,13 @@ func (n *storeNode) removeCredsDir(logger lager.Logger, info executor.Container) } } +func (n *storeNode) removeServiceBindingRoot(logger lager.Logger, info executor.Container) { + err := n.serviceBindingRoot.RemoveDir(logger, info) + if err != nil { + logger.Error("failed-to-delete-service-binding-root-config-dir", err) + } +} + func (n *storeNode) umountVolumeMounts(logger lager.Logger, info executor.Container) { for _, volume := range info.VolumeMounts { err := n.volumeManager.Unmount(logger, volume.Driver, volume.VolumeId, info.Guid) diff --git a/initializer/initializer.go b/initializer/initializer.go index 9209663b..3f108d1b 100644 --- a/initializer/initializer.go +++ b/initializer/initializer.go @@ -149,6 +149,7 @@ type ExecutorConfig struct { UnhealthyMonitoringInterval durationjson.Duration `json:"unhealthy_monitoring_interval,omitempty"` UseSchedulableDiskSize bool `json:"use_schedulable_disk_size,omitempty"` VolmanDriverPaths string `json:"volman_driver_paths"` + ServiceBindingRoot string `json:"service_binding_root"` } var ( @@ -307,6 +308,11 @@ func Initialize(logger lager.Logger, config ExecutorConfig, cellID, zone string, return nil, nil, grouper.Members{}, err } + serviceBindingRootHandler := containerstore.NewServiceBindingRootHandler( + config.ServiceBindingRoot, + "/etc/cf-service-binding-root", + ) + logManager := containerstore.NewLogManager() containerStore := containerstore.New( @@ -329,6 +335,7 @@ func Initialize(logger lager.Logger, config ExecutorConfig, cellID, zone string, cellID, config.EnableUnproxiedPortMappings, config.AdvertisePreferenceForInstanceAddress, + serviceBindingRootHandler, json.Marshal, ) diff --git a/resource_converters.go b/resource_converters.go index c25a9d00..e103991e 100644 --- a/resource_converters.go +++ b/resource_converters.go @@ -19,3 +19,13 @@ func EnvironmentVariablesFromModel(envVars []*models.EnvironmentVariable) []Envi } return out } + +func FilesBasedServiceBindingFromModel(envFiles []*models.Files) []ServiceBindingFiles { + out := make([]ServiceBindingFiles, len(envFiles)) + for i, envFile := range envFiles { + out[i].Name = envFile.Name + out[i].Value = envFile.Value + } + + return out +} diff --git a/resources.go b/resources.go index 05ff52b1..53a5f7f7 100644 --- a/resources.go +++ b/resources.go @@ -199,6 +199,7 @@ type RunInfo struct { EnableContainerProxy bool `json:"enable_container_proxy"` Sidecars []Sidecar `json:"sidecars"` LogRateLimitBytesPerSecond int64 `json:"log_rate_limit_bytes_per_second"` + ServiceBindingFiles []ServiceBindingFiles `json:"service_binding_files,omitempty"` } type BindMountMode uint8 @@ -227,6 +228,11 @@ type EnvironmentVariable struct { Value string `json:"value"` } +type ServiceBindingFiles struct { + Name string `json:"name"` + Value string `json:"value"` +} + type ContainerMetrics struct { MemoryUsageInBytes uint64 `json:"memory_usage_in_bytes"` DiskUsageInBytes uint64 `json:"disk_usage_in_bytes"`