func newSignalableFileLogger(logPath string, level boshlog.LogLevel) boshlog.Logger { // Log file logger errors to the STDERR logger logger := boshlog.NewLogger(boshlog.LevelError) fileSystem := boshsys.NewOsFileSystem(logger) // log file will be closed by process exit // log file readable by all logfileLogger, _, err := boshlogfile.New(level, logPath, boshlogfile.DefaultLogFileMode, fileSystem) if err != nil { logger := boshlog.NewLogger(boshlog.LevelError) ui := biui.NewConsoleUI(logger) fail(err, ui, logger, nil) } return newSignalableLogger(logfileLogger) }
func buildFactory() (factory Factory) { config := davconf.Config{User: "******"} logger := boshlog.NewLogger(boshlog.LevelNone) factory = NewFactory(logger) factory.SetConfig(config) return }
func main() { var cfg *config.Config if configFile != "" { log.Printf("Loading file: %s\n", configFile) cfg = config.InitConfigFromFile(configFile) } else { log.Fatal("Config file not specified.") } level, err := logger.Levelify(cfg.Logging.Level) if err != nil { panic(err.Error()) } logger := logger.NewLogger(level) dnsUpdater := dns.NewDnsUpdater(*cfg, logger) go dnsUpdater.Run() // error chan not being used by anything, just to prevent main from exiting errCh := make(chan error, 1) select { case <-errCh: return } }
func buildSSHAction(settingsService boshsettings.Service) (*fakeplatform.FakePlatform, SSHAction) { platform := fakeplatform.NewFakePlatform() dirProvider := boshdirs.NewProvider("/foo") logger := boshlog.NewLogger(boshlog.LevelNone) action := NewSSH(settingsService, platform, dirProvider, logger) return platform, action }
func NewTestEnvironment( cmdRunner boshsys.CmdRunner, ) *TestEnvironment { return &TestEnvironment{ cmdRunner: cmdRunner, currentDeviceNum: 2, logger: logger.NewLogger(logger.LevelDebug), } }
func runGet(config davconf.Config, args []string) error { logger := boshlog.NewLogger(boshlog.LevelNone) factory := NewFactory(logger) factory.SetConfig(config) cmd, err := factory.Create("get") Expect(err).ToNot(HaveOccurred()) return cmd.Run(args) }
func newLogger() boshlog.Logger { logLevelString := os.Getenv("BOSH_INIT_LOG_LEVEL") level := boshlog.LevelNone if logLevelString != "" { var err error level, err = boshlog.Levelify(logLevelString) if err != nil { err = bosherr.WrapError(err, "Invalid BOSH_INIT_LOG_LEVEL value") logger := boshlog.NewLogger(boshlog.LevelError) ui := biui.NewConsoleUI(logger) fail(err, ui, logger, nil) } } logPath := os.Getenv("BOSH_INIT_LOG_PATH") if logPath != "" { return newSignalableFileLogger(logPath, level) } return newSignalableLogger(boshlog.NewLogger(level)) }
func newFakeClient(shortClient, longClient *fakehttp.FakeClient) Client { logger := boshlog.NewLogger(boshlog.LevelNone) return NewHTTPClient( "agent.example.com", "fake-user", "fake-pass", shortClient, longClient, logger, ) }
func newRealClient(url string) Client { logger := boshlog.NewLogger(boshlog.LevelNone) return NewHTTPClient( url, "fake-user", "fake-pass", http.DefaultClient, http.DefaultClient, logger, ) }
func describeDummyPlatform() { var ( platform Platform collector boshstats.Collector fs boshsys.FileSystem cmdRunner boshsys.CmdRunner dirProvider boshdirs.Provider devicePathResolver boshdpresolv.DevicePathResolver logger boshlog.Logger ) BeforeEach(func() { collector = &fakestats.FakeCollector{} fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() dirProvider = boshdirs.NewProvider("/fake-dir") devicePathResolver = fakedpresolv.NewFakeDevicePathResolver() logger = boshlog.NewLogger(boshlog.LevelNone) }) JustBeforeEach(func() { platform = NewDummyPlatform( collector, fs, cmdRunner, dirProvider, devicePathResolver, logger, ) }) Describe("GetDefaultNetwork", func() { It("returns the contents of dummy-defaults-network-settings.json since that's what the dummy cpi writes", func() { settingsFilePath := "/fake-dir/bosh/dummy-default-network-settings.json" fs.WriteFileString(settingsFilePath, `{"IP": "1.2.3.4"}`) network, err := platform.GetDefaultNetwork() Expect(err).NotTo(HaveOccurred()) Expect(network.IP).To(Equal("1.2.3.4")) }) }) Describe("GetCertManager", func() { It("returs a dummy cert manager", func() { certManager := platform.GetCertManager() Expect(certManager.UpdateCertificates("")).Should(BeNil()) }) }) }
func init() { Describe("Stop", func() { var ( jobSupervisor *fakejobsuper.FakeJobSupervisor platform *fakeplatform.FakePlatform settingsService *fakesettings.FakeSettingsService logger boshlog.Logger specService *fakeas.FakeV1Service dualDCSupport *nimbus.DualDCSupport action StopAction ) BeforeEach(func() { jobSupervisor = fakejobsuper.NewFakeJobSupervisor() platform = fakeplatform.NewFakePlatform() logger = boshlog.NewLogger(boshlog.LevelNone) specService = fakeas.NewFakeV1Service() settingsService = &fakesettings.FakeSettingsService{} dualDCSupport = nimbus.NewDualDCSupport( platform.GetRunner(), platform.GetFs(), platform.GetDirProvider(), specService, settingsService, logger, ) action = NewStop(jobSupervisor, dualDCSupport, platform) }) It("is asynchronous", func() { Expect(action.IsAsynchronous()).To(BeTrue()) }) It("is not persistent", func() { Expect(action.IsPersistent()).To(BeFalse()) }) It("returns stopped", func() { stopped, err := action.Run() Expect(err).ToNot(HaveOccurred()) Expect(stopped).To(Equal("stopped")) }) It("stops job supervisor services", func() { _, err := action.Run() Expect(err).ToNot(HaveOccurred()) Expect(jobSupervisor.Stopped).To(BeTrue()) }) }) }
func main() { logger := boshlog.NewLogger(boshlog.LevelNone) cmdFactory := cmd.NewFactory(logger) cmdRunner := cmd.NewRunner(cmdFactory) cli := app.New(cmdRunner) err := cli.Run(os.Args) if err != nil { fmt.Printf("Error running app - %s", err.Error()) os.Exit(1) } }
func TestIntegration(t *testing.T) { RegisterFailHandler(Fail) BeforeSuite(func() { logger := boshlog.NewLogger(boshlog.LevelDebug) cmdRunner := boshsys.NewExecCmdRunner(logger) testEnvironment = NewTestEnvironment(cmdRunner) // Required for reverse-compatibility with older bosh-lite // (remove once a new warden stemcell is built). err := testEnvironment.ConfigureAgentForGenericInfrastructure() Expect(err).ToNot(HaveOccurred()) }) RunSpecs(t, "Integration Suite") }
//TODO: rename NewBlobstore func (f blobstoreFactory) Create(blobstoreURL string, httpClient *http.Client) (Blobstore, error) { logger := boshlog.NewLogger(boshlog.LevelNone) blobstoreConfig, err := f.parseBlobstoreURL(blobstoreURL) if err != nil { return nil, bosherr.WrapError(err, "Creating blobstore config") } davClient := boshdavcli.NewClient(boshdavcliconf.Config{ Endpoint: fmt.Sprintf("%s/blobs", blobstoreConfig.Endpoint), User: blobstoreConfig.Username, Password: blobstoreConfig.Password, }, httpClient, logger) return NewBlobstore(davClient, f.uuidGenerator, f.fs, f.logger), nil }
func init() { Describe("ListDisk", func() { var ( settingsService *fakesettings.FakeSettingsService platform *fakeplatform.FakePlatform logger boshlog.Logger action ListDiskAction ) BeforeEach(func() { settingsService = &fakesettings.FakeSettingsService{} platform = fakeplatform.NewFakePlatform() logger = boshlog.NewLogger(boshlog.LevelNone) action = NewListDisk(settingsService, platform, logger) }) It("list disk should be synchronous", func() { Expect(action.IsAsynchronous()).To(BeFalse()) }) It("is not persistent", func() { Expect(action.IsPersistent()).To(BeFalse()) }) It("list disk run", func() { platform.MountedDevicePaths = []string{"/dev/sdb", "/dev/sdc"} settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "volume-1": "/dev/sda", "volume-2": "/dev/sdb", "volume-3": "/dev/sdc", }, } value, err := action.Run() Expect(err).ToNot(HaveOccurred()) values, ok := value.([]string) Expect(ok).To(BeTrue()) Expect(values).To(ContainElement("volume-2")) Expect(values).To(ContainElement("volume-3")) Expect(len(values)).To(Equal(2)) }) }) }
func main() { logger := newSignalableLogger(boshlog.NewLogger(boshlog.LevelDebug)) defer logger.HandlePanic("Main") logger.Debug(mainLogTag, "Starting agent") fs := boshsys.NewOsFileSystem(logger) app := boshapp.New(logger, fs) err := app.Setup(os.Args) if err != nil { logger.Error(mainLogTag, "App setup %s", err.Error()) os.Exit(1) } err = app.Run() if err != nil { logger.Error(mainLogTag, "App run %s", err.Error()) os.Exit(1) } }
func main() { user := flag.String("user", "user", "User") password := flag.String("password", "password", "Password") host := flag.String("host", "127.0.0.1", "Host") port := flag.Int("port", 8080, "Port") instance := flag.String("instance", "", "Instance ID") settings := flag.String("settings", "", "Instance Settings") flag.Parse() logger := boshlog.NewLogger(boshlog.LevelDebug) serverManager := bmregistry.NewServerManager(logger) _, err := serverManager.Start(*user, *password, *host, *port) if err != nil { panic("Error starting registry") } if *instance != "" && *settings != "" { request, err := http.NewRequest( "PUT", fmt.Sprintf("http://%s:%s@%s:%d/instances/%s/settings", *user, *password, *host, *port, *instance), strings.NewReader(*settings), ) if err != nil { panic("Couldn't create request") } client := http.DefaultClient _, err = client.Do(request) if err != nil { panic(fmt.Sprintf("Error sending request: %s", err.Error())) } } select {} }
func describeInterfaceConfigurationCreator() { var ( interfaceConfigurationCreator InterfaceConfigurationCreator staticNetwork boshsettings.Network staticNetworkWithoutMAC boshsettings.Network dhcpNetwork boshsettings.Network ) BeforeEach(func() { logger := boshlog.NewLogger(boshlog.LevelNone) interfaceConfigurationCreator = NewInterfaceConfigurationCreator(logger) dhcpNetwork = boshsettings.Network{ Type: "dynamic", Default: []string{"dns"}, DNS: []string{"8.8.8.8", "9.9.9.9"}, Mac: "fake-dhcp-mac-address", } staticNetwork = boshsettings.Network{ IP: "1.2.3.4", Netmask: "255.255.255.0", Gateway: "3.4.5.6", Mac: "fake-static-mac-address", } staticNetworkWithoutMAC = boshsettings.Network{ Type: "manual", IP: "1.2.3.4", Netmask: "255.255.255.0", Gateway: "3.4.5.6", } }) Describe("CreateInterfaceConfigurations", func() { var networks boshsettings.Networks var interfacesByMAC map[string]string BeforeEach(func() { networks = boshsettings.Networks{} interfacesByMAC = map[string]string{} }) Context("One network", func() { Context("And the network has a MAC address", func() { BeforeEach(func() { networks["foo"] = staticNetwork }) Context("And the MAC address matches an interface", func() { BeforeEach(func() { interfacesByMAC[staticNetwork.Mac] = "static-interface-name" }) It("creates an interface configuration when matching interface exists", func() { staticInterfaceConfigurations, dhcpInterfaceConfigurations, err := interfaceConfigurationCreator.CreateInterfaceConfigurations(networks, interfacesByMAC) Expect(err).ToNot(HaveOccurred()) Expect(staticInterfaceConfigurations).To(Equal([]StaticInterfaceConfiguration{ StaticInterfaceConfiguration{ Name: "static-interface-name", Address: "1.2.3.4", Netmask: "255.255.255.0", Network: "1.2.3.0", Broadcast: "1.2.3.255", Mac: "fake-static-mac-address", Gateway: "3.4.5.6", }, })) Expect(len(dhcpInterfaceConfigurations)).To(Equal(0)) }) }) Context("And the MAC address has no matching an interface", func() { BeforeEach(func() { interfacesByMAC["some-other-mac"] = "static-interface-name" }) It("retuns an error", func() { _, _, err := interfaceConfigurationCreator.CreateInterfaceConfigurations(networks, interfacesByMAC) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("No device found")) Expect(err.Error()).To(ContainSubstring(staticNetwork.Mac)) Expect(err.Error()).To(ContainSubstring("foo")) }) }) }) Context("Does not have a MAC address", func() { BeforeEach(func() { networks["foo"] = staticNetworkWithoutMAC }) Context("And at least one device is available", func() { BeforeEach(func() { interfacesByMAC["fake-any-mac-address"] = "any-interface-name" }) It("creates an interface configuration even with the MAC address from first interface with device", func() { staticInterfaceConfigurations, dhcpInterfaceConfigurations, err := interfaceConfigurationCreator.CreateInterfaceConfigurations(networks, interfacesByMAC) Expect(err).ToNot(HaveOccurred()) Expect(staticInterfaceConfigurations).To(Equal([]StaticInterfaceConfiguration{ StaticInterfaceConfiguration{ Name: "any-interface-name", Address: "1.2.3.4", Netmask: "255.255.255.0", Network: "1.2.3.0", Broadcast: "1.2.3.255", Mac: "fake-any-mac-address", Gateway: "3.4.5.6", }, })) Expect(len(dhcpInterfaceConfigurations)).To(Equal(0)) }) }) Context("And there are no network devices", func() { BeforeEach(func() { interfacesByMAC = map[string]string{} }) It("retuns an error", func() { _, _, err := interfaceConfigurationCreator.CreateInterfaceConfigurations(networks, interfacesByMAC) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Number of network settings '1' is greater than the number of network devices '0'")) }) }) }) }) Context("Multiple networks", func() { Context("when the number of networks matches the number of devices", func() { Context("and every interface has a matching networks, by MAC address", func() { BeforeEach(func() { networks["foo"] = staticNetwork networks["bar"] = dhcpNetwork interfacesByMAC[staticNetwork.Mac] = "static-interface-name" interfacesByMAC[dhcpNetwork.Mac] = "dhcp-interface-name" }) It("creates interface configurations for each network when matching interfaces exist", func() { staticInterfaceConfigurations, dhcpInterfaceConfigurations, err := interfaceConfigurationCreator.CreateInterfaceConfigurations(networks, interfacesByMAC) Expect(err).ToNot(HaveOccurred()) Expect(staticInterfaceConfigurations).To(Equal([]StaticInterfaceConfiguration{ StaticInterfaceConfiguration{ Name: "static-interface-name", Address: "1.2.3.4", Netmask: "255.255.255.0", Network: "1.2.3.0", Broadcast: "1.2.3.255", Mac: "fake-static-mac-address", Gateway: "3.4.5.6", }, })) Expect(dhcpInterfaceConfigurations).To(Equal([]DHCPInterfaceConfiguration{ DHCPInterfaceConfiguration{ Name: "dhcp-interface-name", }, })) }) }) Context("and some networks have no MAC address", func() { BeforeEach(func() { networks["foo"] = staticNetworkWithoutMAC networks["bar"] = dhcpNetwork interfacesByMAC["some-other-mac"] = "other-interface-name" interfacesByMAC[dhcpNetwork.Mac] = "dhcp-interface-name" }) It("creates interface configurations for each network when matching interfaces exist, and sets non-matching interfaces as DHCP", func() { staticInterfaceConfigurations, dhcpInterfaceConfigurations, err := interfaceConfigurationCreator.CreateInterfaceConfigurations(networks, interfacesByMAC) Expect(err).ToNot(HaveOccurred()) Expect(staticInterfaceConfigurations).To(BeEmpty()) Expect(dhcpInterfaceConfigurations).To(ConsistOf( DHCPInterfaceConfiguration{ Name: "dhcp-interface-name", }, DHCPInterfaceConfiguration{ Name: "other-interface-name", }, )) }) }) Context("and some networks MAC addresses that don't match", func() { BeforeEach(func() { networks["foo"] = staticNetwork networks["bar"] = dhcpNetwork interfacesByMAC["some-other-mac"] = "static-interface-name" interfacesByMAC[dhcpNetwork.Mac] = "dhcp-interface-name" }) It("retuns an error", func() { _, _, err := interfaceConfigurationCreator.CreateInterfaceConfigurations(networks, interfacesByMAC) Expect(err).To(HaveOccurred()) }) }) }) }) Context("when the number of networks does not match the number of devices", func() { BeforeEach(func() { networks["foo"] = staticNetwork networks["bar"] = dhcpNetwork networks["baz"] = staticNetworkWithoutMAC interfacesByMAC["some-other-mac"] = "static-interface-name" interfacesByMAC[dhcpNetwork.Mac] = "dhcp-interface-name" }) It("retuns an error", func() { _, _, err := interfaceConfigurationCreator.CreateInterfaceConfigurations(networks, interfacesByMAC) Expect(err).To(HaveOccurred()) }) }) }) It("wraps errors calculating Network and Broadcast addresses", func() { invalidNetwork := boshsettings.Network{ Type: "manual", IP: "not an ip", Netmask: "not a valid mask", Mac: "invalid-network-mac-address", } interfacesByMAC := map[string]string{ "invalid-network-mac-address": "static-interface-name", } _, _, err := interfaceConfigurationCreator.CreateInterfaceConfigurations(boshsettings.Networks{"foo": invalidNetwork}, interfacesByMAC) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Invalid ip or netmask")) }) }
func init() { Describe("App", func() { var ( baseDir string agentConfPath string agentConfJSON string app App ) BeforeEach(func() { var err error baseDir, err = ioutil.TempDir("", "go-agent-test") Expect(err).ToNot(HaveOccurred()) err = os.Mkdir(filepath.Join(baseDir, "bosh"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) }) BeforeEach(func() { agentConfPath = filepath.Join(baseDir, "bosh", "agent.json") agentConfJSON = `{ "Infrastructure": { "Settings": { "Sources": [{ "Type": "CDROM", "FileName": "/fake-file-name" }] } } }` settingsPath := filepath.Join(baseDir, "bosh", "settings.json") settingsJSON := `{ "agent_id": "my-agent-id", "blobstore": { "options": { "bucket_name": "george", "encryption_key": "optional encryption key", "access_key_id": "optional access key id", "secret_access_key": "optional secret access key" }, "provider": "dummy" }, "disks": { "ephemeral": "/dev/sdb", "persistent": { "vol-xxxxxx": "/dev/sdf" }, "system": "/dev/sda1" }, "env": { "bosh": { "password": "******" } }, "networks": { "netA": { "default": ["dns", "gateway"], "ip": "ww.ww.ww.ww", "dns": [ "xx.xx.xx.xx", "yy.yy.yy.yy" ] }, "netB": { "dns": [ "zz.zz.zz.zz" ] } }, "Mbus": "https://*****:*****@0.0.0.0:6868", "ntp": [ "0.north-america.pool.ntp.org", "1.north-america.pool.ntp.org" ], "vm": { "name": "vm-abc-def" } }` err := ioutil.WriteFile(settingsPath, []byte(settingsJSON), 0640) Expect(err).ToNot(HaveOccurred()) }) JustBeforeEach(func() { err := ioutil.WriteFile(agentConfPath, []byte(agentConfJSON), 0640) Expect(err).ToNot(HaveOccurred()) logger := boshlog.NewLogger(boshlog.LevelNone) fakefs := boshsys.NewOsFileSystem(logger) app = New(logger, fakefs) }) AfterEach(func() { os.RemoveAll(baseDir) }) It("Sets up device path resolver on platform specific to infrastructure", func() { err := app.Setup([]string{"bosh-agent", "-P", "dummy", "-C", agentConfPath, "-b", baseDir}) Expect(err).ToNot(HaveOccurred()) Expect(app.GetPlatform().GetDevicePathResolver()).To(Equal(devicepathresolver.NewIdentityDevicePathResolver())) }) Context("when DevicePathResolutionType is 'virtio'", func() { BeforeEach(func() { agentConfJSON = `{ "Platform": { "Linux": { "DevicePathResolutionType": "virtio" } }, "Infrastructure": { "Settings": { "Sources": [{ "Type": "CDROM", "FileName": "/fake-file-name" }] } } }` }) It("uses a VirtioDevicePathResolver", func() { err := app.Setup([]string{"bosh-agent", "-P", "dummy", "-C", agentConfPath, "-b", baseDir}) Expect(err).ToNot(HaveOccurred()) logLevel, err := boshlog.Levelify("DEBUG") Expect(err).NotTo(HaveOccurred()) Expect(app.GetPlatform().GetDevicePathResolver()).To( BeAssignableToTypeOf(devicepathresolver.NewVirtioDevicePathResolver(nil, nil, boshlog.NewLogger(logLevel)))) }) }) Context("when DevicePathResolutionType is 'scsi'", func() { BeforeEach(func() { agentConfJSON = `{ "Platform": { "Linux": { "DevicePathResolutionType": "scsi" } }, "Infrastructure": { "Settings": { "Sources": [{ "Type": "CDROM", "FileName": "/fake-file-name" }] } } }` }) It("uses a VirtioDevicePathResolver", func() { err := app.Setup([]string{"bosh-agent", "-P", "dummy", "-C", agentConfPath, "-b", baseDir}) Expect(err).ToNot(HaveOccurred()) Expect(app.GetPlatform().GetDevicePathResolver()).To( BeAssignableToTypeOf(devicepathresolver.NewScsiDevicePathResolver(nil, nil, nil))) }) }) Context("logging stemcell version and git sha", func() { var ( logger boshlog.Logger outBuf *bytes.Buffer fakeFs boshsys.FileSystem stemcellVersionFilePath string stemcellSha1FilePath string ) JustBeforeEach(func() { outBuf = bytes.NewBufferString("") errBuf := bytes.NewBufferString("") logger = boshlog.NewWriterLogger(boshlog.LevelDebug, outBuf, errBuf) fakeFs = fakesys.NewFakeFileSystem() dirProvider := boshdirs.NewProvider(baseDir) stemcellVersionFilePath = filepath.Join(dirProvider.EtcDir(), "stemcell_version") stemcellSha1FilePath = filepath.Join(dirProvider.EtcDir(), "stemcell_git_sha1") app = New(logger, fakeFs) }) Context("when stemcell version and sha files are present", func() { It("should print out the stemcell version and sha in the logs", func() { fakeFs.WriteFileString(stemcellVersionFilePath, "version-blah") fakeFs.WriteFileString(stemcellSha1FilePath, "sha1-blah") app.Setup([]string{"bosh-agent", "-P", "dummy", "-C", agentConfPath, "-b", baseDir}) Expect(string(outBuf.Bytes())).To(ContainSubstring("Running on stemcell version 'version-blah' (git: sha1-blah)")) }) }) Context("when stemcell version file is NOT present", func() { It("should print out the sha in the logs", func() { fakeFs.WriteFileString(stemcellSha1FilePath, "sha1-blah") app.Setup([]string{"bosh-agent", "-P", "dummy", "-C", agentConfPath, "-b", baseDir}) Expect(string(outBuf.Bytes())).To(ContainSubstring("Running on stemcell version '?' (git: sha1-blah)")) }) }) Context("when sha version file is NOT present", func() { It("should print out the stemcell version in the logs", func() { fakeFs.WriteFileString(stemcellVersionFilePath, "version-blah") app.Setup([]string{"bosh-agent", "-P", "dummy", "-C", agentConfPath, "-b", baseDir}) Expect(string(outBuf.Bytes())).To(ContainSubstring("Running on stemcell version 'version-blah' (git: ?)")) }) }) Context("when stemcell version file is empty", func() { It("should print out the sha in the logs", func() { fakeFs.WriteFileString(stemcellVersionFilePath, "") fakeFs.WriteFileString(stemcellSha1FilePath, "sha1-blah") app.Setup([]string{"bosh-agent", "-P", "dummy", "-C", agentConfPath, "-b", baseDir}) Expect(string(outBuf.Bytes())).To(ContainSubstring("Running on stemcell version '?' (git: sha1-blah)")) }) }) Context("when sha version file is empty", func() { It("should print out the stemcell version in the logs", func() { fakeFs.WriteFileString(stemcellVersionFilePath, "version-blah") fakeFs.WriteFileString(stemcellSha1FilePath, "") app.Setup([]string{"bosh-agent", "-P", "dummy", "-C", agentConfPath, "-b", baseDir}) Expect(string(outBuf.Bytes())).To(ContainSubstring("Running on stemcell version 'version-blah' (git: ?)")) }) }) Context("when stemcell version and sha files are NOT present", func() { It("should print unknown version and sha in the logs", func() { app.Setup([]string{"bosh-agent", "-P", "dummy", "-C", agentConfPath, "-b", baseDir}) Expect(string(outBuf.Bytes())).To(ContainSubstring("Running on stemcell version '?' (git: ?)")) }) }) }) }) }
func init() { Describe("Testing with Ginkgo", func() { It("home dir", func() { osFs, _ := createOsFs() homeDir, err := osFs.HomeDir("root") Expect(err).ToNot(HaveOccurred()) Expect(homeDir).To(ContainSubstring("/root")) }) It("expand path", func() { osFs, _ := createOsFs() expandedPath, err := osFs.ExpandPath("~/fake-dir/fake-file.txt") Expect(err).ToNot(HaveOccurred()) currentUser, err := osuser.Current() Expect(err).ToNot(HaveOccurred()) Expect(expandedPath).To(Equal(currentUser.HomeDir + "/fake-dir/fake-file.txt")) expandedPath, err = osFs.ExpandPath("/fake-dir//fake-file.txt") Expect(err).ToNot(HaveOccurred()) Expect(expandedPath).To(Equal("/fake-dir/fake-file.txt")) expandedPath, err = osFs.ExpandPath("./fake-file.txt") Expect(err).ToNot(HaveOccurred()) currentDir, err := os.Getwd() Expect(err).ToNot(HaveOccurred()) Expect(expandedPath).To(Equal(currentDir + "/fake-file.txt")) }) It("mkdir all", func() { osFs, _ := createOsFs() tmpPath := os.TempDir() testPath := filepath.Join(tmpPath, "MkdirAllTestDir", "bar", "baz") defer os.RemoveAll(filepath.Join(tmpPath, "MkdirAllTestDir")) _, err := os.Stat(testPath) Expect(err).To(HaveOccurred()) Expect(os.IsNotExist(err)).To(BeTrue()) fileMode := os.FileMode(0700) err = osFs.MkdirAll(testPath, fileMode) Expect(err).ToNot(HaveOccurred()) stat, err := os.Stat(testPath) Expect(err).ToNot(HaveOccurred()) Expect(stat.IsDir()).To(BeTrue()) Expect(stat.Mode().Perm()).To(Equal(fileMode)) err = osFs.MkdirAll(testPath, fileMode) Expect(err).ToNot(HaveOccurred()) }) It("chown", func() { osFs, _ := createOsFs() testPath := filepath.Join(os.TempDir(), "ChownTestDir") err := os.Mkdir(testPath, os.FileMode(0700)) Expect(err).ToNot(HaveOccurred()) defer os.RemoveAll(testPath) err = osFs.Chown(testPath, "garbage-foo") Expect(err).To(HaveOccurred()) }) It("chmod", func() { osFs, _ := createOsFs() testPath := filepath.Join(os.TempDir(), "ChmodTestDir") _, err := os.Create(testPath) Expect(err).ToNot(HaveOccurred()) defer os.Remove(testPath) os.Chmod(testPath, os.FileMode(0666)) err = osFs.Chmod(testPath, os.FileMode(0644)) Expect(err).ToNot(HaveOccurred()) fileStat, err := os.Stat(testPath) Expect(err).ToNot(HaveOccurred()) Expect(fileStat.Mode()).To(Equal(os.FileMode(0644))) }) It("opens file", func() { osFs, _ := createOsFs() testPath := filepath.Join(os.TempDir(), "OpenFileTestFile") file, err := osFs.OpenFile(testPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.FileMode(0644)) defer os.Remove(testPath) Expect(err).ToNot(HaveOccurred()) file.Write([]byte("testing new file")) file.Close() createdFile, err := os.Open(testPath) Expect(err).ToNot(HaveOccurred()) defer createdFile.Close() Expect(readFile(createdFile)).To(Equal("testing new file")) }) Context("the file already exists and is not write only", func() { It("writes to file", func() { osFs, _ := createOsFs() testPath := filepath.Join(os.TempDir(), "subDir", "ConvergeFileContentsTestFile") _, err := os.Stat(testPath) Expect(err).To(HaveOccurred()) written, err := osFs.ConvergeFileContents(testPath, []byte("initial write")) Expect(err).ToNot(HaveOccurred()) Expect(written).To(BeTrue()) defer os.Remove(testPath) file, err := os.Open(testPath) Expect(err).ToNot(HaveOccurred()) defer file.Close() Expect(readFile(file)).To(Equal("initial write")) written, err = osFs.ConvergeFileContents(testPath, []byte("second write")) Expect(err).ToNot(HaveOccurred()) Expect(written).To(BeTrue()) file.Close() file, err = os.Open(testPath) Expect(err).ToNot(HaveOccurred()) Expect(readFile(file)).To(Equal("second write")) file.Close() file, err = os.Open(testPath) written, err = osFs.ConvergeFileContents(testPath, []byte("second write")) Expect(err).ToNot(HaveOccurred()) Expect(written).To(BeFalse()) Expect(readFile(file)).To(Equal("second write")) }) }) Context("the file already exists and is write only", func() { It("writes to file", func() { osFs, _ := createOsFs() testPath := filepath.Join(os.TempDir(), "subDir", "ConvergeFileContentsTestFile") _, err := os.OpenFile(testPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(0200)) Expect(err).ToNot(HaveOccurred()) defer os.Remove(testPath) err = osFs.WriteFile(testPath, []byte("test")) Expect(err).ToNot(HaveOccurred()) }) }) Context("the file parent fir does not exist", func() { BeforeEach(func() { err := os.RemoveAll(filepath.Join(os.TempDir(), "subDirNew")) Expect(err).ToNot(HaveOccurred()) }) AfterEach(func() { err := os.RemoveAll(filepath.Join(os.TempDir(), "subDirNew")) Expect(err).ToNot(HaveOccurred()) }) It("writes to file", func() { osFs, _ := createOsFs() testPath := filepath.Join(os.TempDir(), "subDirNew", "ConvergeFileContentsTestFile") err := osFs.WriteFile(testPath, []byte("test")) Expect(err).ToNot(HaveOccurred()) }) }) It("read file", func() { osFs, _ := createOsFs() testPath := filepath.Join(os.TempDir(), "ReadFileTestFile") osFs.WriteFileString(testPath, "some contents") defer os.Remove(testPath) content, err := osFs.ReadFile(testPath) Expect(err).ToNot(HaveOccurred()) Expect("some contents").To(Equal(string(content))) }) It("file exists", func() { osFs, _ := createOsFs() testPath := filepath.Join(os.TempDir(), "FileExistsTestFile") Expect(osFs.FileExists(testPath)).To(BeFalse()) osFs.WriteFileString(testPath, "initial write") defer os.Remove(testPath) Expect(osFs.FileExists(testPath)).To(BeTrue()) }) It("rename", func() { osFs, _ := createOsFs() tempDir := os.TempDir() oldPath := filepath.Join(tempDir, "old") oldFilePath := filepath.Join(oldPath, "test.txt") newPath := filepath.Join(tempDir, "new") os.Mkdir(oldPath, os.ModePerm) _, err := os.Create(oldFilePath) Expect(err).ToNot(HaveOccurred()) err = osFs.Rename(oldPath, newPath) Expect(err).ToNot(HaveOccurred()) Expect(osFs.FileExists(newPath)).To(BeTrue()) newFilePath := filepath.Join(newPath, "test.txt") Expect(osFs.FileExists(newFilePath)).To(BeTrue()) }) It("symlink", func() { osFs, _ := createOsFs() filePath := filepath.Join(os.TempDir(), "SymlinkTestFile") containingDir := filepath.Join(os.TempDir(), "SubDir") os.Remove(containingDir) symlinkPath := filepath.Join(containingDir, "SymlinkTestSymlink") osFs.WriteFileString(filePath, "some content") defer os.Remove(filePath) osFs.Symlink(filePath, symlinkPath) defer os.Remove(containingDir) symlinkStats, err := os.Lstat(symlinkPath) Expect(err).ToNot(HaveOccurred()) Expect(os.ModeSymlink).To(Equal(os.ModeSymlink & symlinkStats.Mode())) symlinkFile, err := os.Open(symlinkPath) Expect(err).ToNot(HaveOccurred()) Expect("some content").To(Equal(readFile(symlinkFile))) }) It("symlink when link already exists and links to the intended path", func() { osFs, _ := createOsFs() filePath := filepath.Join(os.TempDir(), "SymlinkTestIdempotent1File") symlinkPath := filepath.Join(os.TempDir(), "SymlinkTestIdempotent1Symlink") osFs.WriteFileString(filePath, "some content") defer os.Remove(filePath) osFs.Symlink(filePath, symlinkPath) defer os.Remove(symlinkPath) firstSymlinkStats, err := os.Lstat(symlinkPath) Expect(err).ToNot(HaveOccurred()) err = osFs.Symlink(filePath, symlinkPath) Expect(err).ToNot(HaveOccurred()) secondSymlinkStats, err := os.Lstat(symlinkPath) Expect(err).ToNot(HaveOccurred()) Expect(firstSymlinkStats.ModTime()).To(Equal(secondSymlinkStats.ModTime())) }) It("symlink when link already exists and does not link to the intended path", func() { osFs, _ := createOsFs() filePath := filepath.Join(os.TempDir(), "SymlinkTestIdempotent1File") otherFilePath := filepath.Join(os.TempDir(), "SymlinkTestIdempotent1OtherFile") symlinkPath := filepath.Join(os.TempDir(), "SymlinkTestIdempotent1Symlink") osFs.WriteFileString(filePath, "some content") defer os.Remove(filePath) osFs.WriteFileString(otherFilePath, "other content") defer os.Remove(otherFilePath) err := osFs.Symlink(otherFilePath, symlinkPath) Expect(err).ToNot(HaveOccurred()) err = osFs.Symlink(filePath, symlinkPath) Expect(err).ToNot(HaveOccurred()) defer os.Remove(symlinkPath) symlinkStats, err := os.Lstat(symlinkPath) Expect(err).ToNot(HaveOccurred()) Expect(os.ModeSymlink).To(Equal(os.ModeSymlink & symlinkStats.Mode())) symlinkFile, err := os.Open(symlinkPath) Expect(err).ToNot(HaveOccurred()) Expect("some content").To(Equal(readFile(symlinkFile))) }) It("symlink when a file exists at intended path", func() { osFs, _ := createOsFs() filePath := filepath.Join(os.TempDir(), "SymlinkTestIdempotent1File") symlinkPath := filepath.Join(os.TempDir(), "SymlinkTestIdempotent1Symlink") osFs.WriteFileString(filePath, "some content") defer os.Remove(filePath) osFs.WriteFileString(symlinkPath, "some other content") defer os.Remove(symlinkPath) err := osFs.Symlink(filePath, symlinkPath) Expect(err).ToNot(HaveOccurred()) defer os.Remove(symlinkPath) symlinkStats, err := os.Lstat(symlinkPath) Expect(err).ToNot(HaveOccurred()) Expect(os.ModeSymlink).To(Equal(os.ModeSymlink & symlinkStats.Mode())) symlinkFile, err := os.Open(symlinkPath) Expect(err).ToNot(HaveOccurred()) Expect("some content").To(Equal(readFile(symlinkFile))) }) It("read link", func() { osFs, _ := createOsFs() filePath := filepath.Join(os.TempDir(), "SymlinkTestFile") containingDir := filepath.Join(os.TempDir(), "SubDir") os.Remove(containingDir) symlinkPath := filepath.Join(containingDir, "SymlinkTestSymlink") osFs.WriteFileString(filePath, "some content") defer os.Remove(filePath) err := osFs.Symlink(filePath, symlinkPath) Expect(err).ToNot(HaveOccurred()) defer os.Remove(containingDir) actualFilePath, err := osFs.ReadLink(symlinkPath) Expect(err).ToNot(HaveOccurred()) // on Mac OS /var -> private/var absPath, err := filepath.EvalSymlinks(filePath) Expect(err).ToNot(HaveOccurred()) Expect(actualFilePath).To(Equal(absPath)) }) It("temp file", func() { osFs, _ := createOsFs() file1, err := osFs.TempFile("fake-prefix") Expect(err).ToNot(HaveOccurred()) assert.NotEmpty(GinkgoT(), file1) defer os.Remove(file1.Name()) file2, err := osFs.TempFile("fake-prefix") Expect(err).ToNot(HaveOccurred()) assert.NotEmpty(GinkgoT(), file2) defer os.Remove(file2.Name()) assert.NotEqual(GinkgoT(), file1.Name(), file2.Name()) }) It("temp dir", func() { osFs, _ := createOsFs() path1, err := osFs.TempDir("fake-prefix") Expect(err).ToNot(HaveOccurred()) assert.NotEmpty(GinkgoT(), path1) defer os.Remove(path1) path2, err := osFs.TempDir("fake-prefix") Expect(err).ToNot(HaveOccurred()) assert.NotEmpty(GinkgoT(), path2) defer os.Remove(path2) assert.NotEqual(GinkgoT(), path1, path2) }) Describe("Temporary directories and files", func() { var ( osFs FileSystem testTempDir string ) BeforeEach(func() { osFs, _ = createOsFs() var err error testTempDir, err = ioutil.TempDir("", "os_filesystem_test") Expect(err).ToNot(HaveOccurred()) }) AfterEach(func() { os.Remove(testTempDir) }) Context("a temp root is set", func() { BeforeEach(func() { osFs.ChangeTempRoot(testTempDir) }) It("creates temp files under that root", func() { file, err := osFs.TempFile("some-file-prefix") Expect(err).ToNot(HaveOccurred()) Expect(file.Name()).To(HavePrefix(filepath.Join(testTempDir, "some-file-prefix"))) }) It("creates temp directories under that root", func() { dirName, err := osFs.TempDir("some-dir-prefix") Expect(err).ToNot(HaveOccurred()) Expect(dirName).To(HavePrefix(filepath.Join(testTempDir, "some-dir-prefix"))) }) }) Context("no temp root is set and was initialized as a strict temp root", func() { BeforeEach(func() { osFs = NewOsFileSystemWithStrictTempRoot(boshlog.NewLogger(boshlog.LevelNone)) }) It("should eror", func() { _, err := osFs.TempFile("some-prefix") Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("ChangeTempRoot")) _, err = osFs.TempDir("some-prefix") Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("ChangeTempRoot")) }) }) }) Describe("CopyFile", func() { It("copies file", func() { osFs, _ := createOsFs() srcPath := "test_assets/test_copy_dir_entries/foo.txt" dstFile, err := osFs.TempFile("CopyFileTestFile") Expect(err).ToNot(HaveOccurred()) defer os.Remove(dstFile.Name()) err = osFs.CopyFile(srcPath, dstFile.Name()) fooContent, err := osFs.ReadFileString(dstFile.Name()) Expect(err).ToNot(HaveOccurred()) Expect(fooContent).To(Equal("foo\n")) }) It("does not leak file descriptors", func() { osFs, _ := createOsFs() srcFile, err := osFs.TempFile("srcPath") Expect(err).ToNot(HaveOccurred()) err = srcFile.Close() Expect(err).ToNot(HaveOccurred()) dstFile, err := osFs.TempFile("dstPath") Expect(err).ToNot(HaveOccurred()) err = dstFile.Close() Expect(err).ToNot(HaveOccurred()) err = osFs.CopyFile(srcFile.Name(), dstFile.Name()) Expect(err).ToNot(HaveOccurred()) runner := NewExecCmdRunner(boshlog.NewLogger(boshlog.LevelNone)) stdout, _, _, err := runner.RunCommand("lsof") Expect(err).ToNot(HaveOccurred()) for _, line := range strings.Split(stdout, "\n") { if strings.Contains(line, srcFile.Name()) { Fail(fmt.Sprintf("CopyFile did not close: srcFile: %s", srcFile.Name())) } if strings.Contains(line, dstFile.Name()) { Fail(fmt.Sprintf("CopyFile did not close: dstFile: %s", dstFile.Name())) } } os.Remove(srcFile.Name()) os.Remove(dstFile.Name()) }) }) Describe("CopyDir", func() { var fixtureFiles = []string{ "foo.txt", "bar/bar.txt", "bar/baz/.gitkeep", } It("recursively copies directory contents", func() { osFs, _ := createOsFs() srcPath := "test_assets/test_copy_dir_entries" dstPath, err := osFs.TempDir("CopyDirTestDir") Expect(err).ToNot(HaveOccurred()) defer osFs.RemoveAll(dstPath) err = osFs.CopyDir(srcPath, dstPath) Expect(err).ToNot(HaveOccurred()) for _, fixtureFile := range fixtureFiles { srcContents, err := osFs.ReadFile(filepath.Join(srcPath, fixtureFile)) Expect(err).ToNot(HaveOccurred()) dstContents, err := osFs.ReadFile(filepath.Join(dstPath, fixtureFile)) Expect(err).ToNot(HaveOccurred()) Expect(srcContents).To(Equal(dstContents), "Copied file does not match source file: '%s", fixtureFile) } }) It("does not leak file descriptors", func() { osFs, _ := createOsFs() srcPath := "test_assets/test_copy_dir_entries" dstPath, err := osFs.TempDir("CopyDirTestDir") Expect(err).ToNot(HaveOccurred()) defer osFs.RemoveAll(dstPath) err = osFs.CopyDir(srcPath, dstPath) Expect(err).ToNot(HaveOccurred()) runner := NewExecCmdRunner(boshlog.NewLogger(boshlog.LevelNone)) stdout, _, _, err := runner.RunCommand("lsof") Expect(err).ToNot(HaveOccurred()) // lsof uses absolute paths srcPath, err = filepath.Abs(srcPath) Expect(err).ToNot(HaveOccurred()) for _, line := range strings.Split(stdout, "\n") { for _, fixtureFile := range fixtureFiles { srcFilePath := filepath.Join(srcPath, fixtureFile) if strings.Contains(line, srcFilePath) { Fail(fmt.Sprintf("CopyDir did not close source file: %s", srcFilePath)) } srcFileDirPath := filepath.Dir(srcFilePath) if strings.Contains(line, srcFileDirPath) { Fail(fmt.Sprintf("CopyDir did not close source dir: %s", srcFileDirPath)) } dstFilePath := filepath.Join(dstPath, fixtureFile) if strings.Contains(line, dstFilePath) { Fail(fmt.Sprintf("CopyDir did not close destination file: %s", dstFilePath)) } dstFileDirPath := filepath.Dir(dstFilePath) if strings.Contains(line, dstFileDirPath) { Fail(fmt.Sprintf("CopyDir did not close destination dir: %s", dstFileDirPath)) } } } }) }) It("remove all", func() { osFs, _ := createOsFs() dstFile, err := osFs.TempFile("CopyFileTestFile") Expect(err).ToNot(HaveOccurred()) defer os.Remove(dstFile.Name()) err = osFs.RemoveAll(dstFile.Name()) Expect(err).ToNot(HaveOccurred()) _, err = os.Stat(dstFile.Name()) Expect(os.IsNotExist(err)).To(BeTrue()) }) }) }
func createOsFs() (fs FileSystem, runner CmdRunner) { logger := boshlog.NewLogger(boshlog.LevelNone) fs = NewOsFileSystem(logger) return }
func init() { Describe("Agent", func() { var ( logger boshlog.Logger handler *fakembus.FakeHandler platform *fakeplatform.FakePlatform actionDispatcher *fakeagent.FakeActionDispatcher jobSupervisor *fakejobsuper.FakeJobSupervisor specService *fakeas.FakeV1Service syslogServer *fakesyslog.FakeServer settingsService *fakesettings.FakeSettingsService uuidGenerator *fakeuuid.FakeGenerator timeService *fakeclock.FakeClock agent Agent ) BeforeEach(func() { logger = boshlog.NewLogger(boshlog.LevelNone) handler = &fakembus.FakeHandler{} platform = fakeplatform.NewFakePlatform() actionDispatcher = &fakeagent.FakeActionDispatcher{} jobSupervisor = fakejobsuper.NewFakeJobSupervisor() specService = fakeas.NewFakeV1Service() syslogServer = &fakesyslog.FakeServer{} settingsService = &fakesettings.FakeSettingsService{} uuidGenerator = &fakeuuid.FakeGenerator{} timeService = fakeclock.NewFakeClock(time.Now()) agent = New( logger, handler, platform, actionDispatcher, jobSupervisor, specService, syslogServer, 5*time.Millisecond, settingsService, uuidGenerator, timeService, ) }) Describe("Run", func() { It("lets dispatcher handle requests arriving via handler", func() { err := agent.Run() Expect(err).ToNot(HaveOccurred()) expectedResp := boshhandler.NewValueResponse("pong") actionDispatcher.DispatchResp = expectedResp req := boshhandler.NewRequest("fake-reply", "fake-action", []byte("fake-payload")) resp := handler.RunFunc(req) Expect(actionDispatcher.DispatchReq).To(Equal(req)) Expect(resp).To(Equal(expectedResp)) }) It("resumes persistent actions *before* dispatching new requests", func() { resumedBeforeStartingToDispatch := false handler.RunCallBack = func() { resumedBeforeStartingToDispatch = actionDispatcher.ResumedPreviouslyDispatchedTasks } err := agent.Run() Expect(err).ToNot(HaveOccurred()) Expect(resumedBeforeStartingToDispatch).To(BeTrue()) }) Context("when heartbeats can be sent", func() { BeforeEach(func() { handler.KeepOnRunning() }) BeforeEach(func() { jobName := "fake-job" nodeID := "node-id" jobIndex := 1 specService.Spec = boshas.V1ApplySpec{ JobSpec: boshas.JobSpec{Name: &jobName}, Index: &jobIndex, NodeID: nodeID, } jobSupervisor.StatusStatus = "fake-state" platform.FakeVitalsService.GetVitals = boshvitals.Vitals{ Load: []string{"a", "b", "c"}, } }) expectedJobName := "fake-job" expectedJobIndex := 1 expectedNodeID := "node-id" expectedHb := Heartbeat{ Job: &expectedJobName, Index: &expectedJobIndex, JobState: "fake-state", NodeID: expectedNodeID, Vitals: boshvitals.Vitals{Load: []string{"a", "b", "c"}}, } It("sends initial heartbeat", func() { // Configure periodic heartbeat every 5 hours // so that we are sure that we will not receive it agent = New( logger, handler, platform, actionDispatcher, jobSupervisor, specService, syslogServer, 5*time.Hour, settingsService, uuidGenerator, timeService, ) // Immediately exit after sending initial heartbeat handler.SendErr = errors.New("stop") err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("stop")) Expect(handler.SendInputs()).To(Equal([]fakembus.SendInput{ { Target: boshhandler.HealthMonitor, Topic: boshhandler.Heartbeat, Message: expectedHb, }, })) }) It("sends periodic heartbeats", func() { sentRequests := 0 handler.SendCallback = func(_ fakembus.SendInput) { sentRequests++ if sentRequests == 3 { handler.SendErr = errors.New("stop") } } err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("stop")) Expect(handler.SendInputs()).To(Equal([]fakembus.SendInput{ { Target: boshhandler.HealthMonitor, Topic: boshhandler.Heartbeat, Message: expectedHb, }, { Target: boshhandler.HealthMonitor, Topic: boshhandler.Heartbeat, Message: expectedHb, }, { Target: boshhandler.HealthMonitor, Topic: boshhandler.Heartbeat, Message: expectedHb, }, })) }) }) Context("when the agent fails to get job spec for a heartbeat", func() { BeforeEach(func() { specService.GetErr = errors.New("fake-spec-service-error") handler.KeepOnRunning() }) It("returns the error", func() { err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-spec-service-error")) }) }) Context("when the agent fails to get vitals for a heartbeat", func() { BeforeEach(func() { platform.FakeVitalsService.GetErr = errors.New("fake-vitals-service-error") handler.KeepOnRunning() }) It("returns the error", func() { err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-vitals-service-error")) }) }) It("sends job monitoring alerts to health manager", func() { handler.KeepOnRunning() monitAlert := boshalert.MonitAlert{ ID: "fake-monit-alert", Service: "fake-service", Event: "fake-event", Action: "fake-action", Date: "Sun, 22 May 2011 20:07:41 +0500", Description: "fake-description", } jobSupervisor.JobFailureAlert = &monitAlert // Fail the first time handler.Send is called for an alert (ignore heartbeats) handler.SendCallback = func(input fakembus.SendInput) { if input.Topic == boshhandler.Alert { handler.SendErr = errors.New("stop") } } err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("stop")) expectedAlert := boshalert.Alert{ ID: "fake-monit-alert", Severity: boshalert.SeverityDefault, Title: "fake-service - fake-event - fake-action", Summary: "fake-description", CreatedAt: int64(1306076861), } Expect(handler.SendInputs()).To(ContainElement(fakembus.SendInput{ Target: boshhandler.HealthMonitor, Topic: boshhandler.Alert, Message: expectedAlert, })) }) It("sends ssh alerts to health manager", func() { handler.KeepOnRunning() syslogMsg := boshsyslog.Msg{Content: "disconnected by user"} syslogServer.StartFirstSyslogMsg = &syslogMsg uuidGenerator.GeneratedUUID = "fake-uuid" // Fail the first time handler.Send is called for an alert (ignore heartbeats) handler.SendCallback = func(input fakembus.SendInput) { if input.Topic == boshhandler.Alert { handler.SendErr = errors.New("stop") } } err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("stop")) expectedAlert := boshalert.Alert{ ID: "fake-uuid", Severity: boshalert.SeverityWarning, Title: "SSH Logout", Summary: "disconnected by user", CreatedAt: timeService.Now().Unix(), } Expect(handler.SendInputs()).To(ContainElement(fakembus.SendInput{ Target: boshhandler.HealthMonitor, Topic: boshhandler.Alert, Message: expectedAlert, })) }) }) }) }
func init() { Describe("settingsService", func() { var ( fs *fakesys.FakeFileSystem fakeDefaultNetworkResolver *fakenet.FakeDefaultNetworkResolver fakeSettingsSource *fakes.FakeSettingsSource ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() fakeDefaultNetworkResolver = &fakenet.FakeDefaultNetworkResolver{} fakeSettingsSource = &fakes.FakeSettingsSource{} }) buildService := func() (Service, *fakesys.FakeFileSystem) { logger := boshlog.NewLogger(boshlog.LevelNone) service := NewService(fs, "/setting/path.json", fakeSettingsSource, fakeDefaultNetworkResolver, logger) return service, fs } Describe("LoadSettings", func() { var ( fetchedSettings Settings fetcherFuncErr error service Service ) BeforeEach(func() { fetchedSettings = Settings{} fetcherFuncErr = nil }) JustBeforeEach(func() { fakeSettingsSource.SettingsValue = fetchedSettings fakeSettingsSource.SettingsErr = fetcherFuncErr service, fs = buildService() }) Context("when settings fetcher succeeds fetching settings", func() { BeforeEach(func() { fetchedSettings = Settings{AgentID: "some-new-agent-id"} }) Context("when settings contain at most one dynamic network", func() { BeforeEach(func() { fetchedSettings.Networks = Networks{ "fake-net-1": Network{Type: NetworkTypeDynamic}, } }) It("updates the service with settings from the fetcher", func() { err := service.LoadSettings() Expect(err).NotTo(HaveOccurred()) Expect(service.GetSettings().AgentID).To(Equal("some-new-agent-id")) }) It("persists settings to the settings file", func() { err := service.LoadSettings() Expect(err).NotTo(HaveOccurred()) json, err := json.Marshal(fetchedSettings) Expect(err).NotTo(HaveOccurred()) fileContent, err := fs.ReadFile("/setting/path.json") Expect(err).NotTo(HaveOccurred()) Expect(fileContent).To(Equal(json)) }) It("returns any error from writing to the setting file", func() { fs.WriteFileError = errors.New("fs-write-file-error") err := service.LoadSettings() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fs-write-file-error")) }) }) }) Context("when settings fetcher fails fetching settings", func() { BeforeEach(func() { fetcherFuncErr = errors.New("fake-fetch-error") }) Context("when a settings file exists", func() { Context("when settings contain at most one dynamic network", func() { BeforeEach(func() { fs.WriteFile("/setting/path.json", []byte(`{ "agent_id":"some-agent-id", "networks": {"fake-net-1": {"type": "dynamic"}} }`)) fakeDefaultNetworkResolver.GetDefaultNetworkNetwork = Network{ IP: "fake-resolved-ip", Netmask: "fake-resolved-netmask", Gateway: "fake-resolved-gateway", } }) It("returns settings from the settings file with resolved network", func() { err := service.LoadSettings() Expect(err).ToNot(HaveOccurred()) Expect(service.GetSettings()).To(Equal(Settings{ AgentID: "some-agent-id", Networks: Networks{ "fake-net-1": Network{ Type: NetworkTypeDynamic, IP: "fake-resolved-ip", Netmask: "fake-resolved-netmask", Gateway: "fake-resolved-gateway", Resolved: true, }, }, })) }) }) }) Context("when non-unmarshallable settings file exists", func() { It("returns any error from the fetcher", func() { fs.WriteFile("/setting/path.json", []byte(`$%^&*(`)) err := service.LoadSettings() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-fetch-error")) Expect(service.GetSettings()).To(Equal(Settings{})) }) }) Context("when no settings file exists", func() { It("returns any error from the fetcher", func() { err := service.LoadSettings() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-fetch-error")) Expect(service.GetSettings()).To(Equal(Settings{})) }) }) }) }) Describe("InvalidateSettings", func() { It("removes the settings file", func() { fakeSettingsSource.SettingsValue = Settings{} fakeSettingsSource.SettingsErr = nil service, fs := buildService() fs.WriteFile("/setting/path.json", []byte(`{}`)) err := service.InvalidateSettings() Expect(err).ToNot(HaveOccurred()) Expect(fs.FileExists("/setting/path.json")).To(BeFalse()) }) It("returns err if removing settings file errored", func() { fakeSettingsSource.SettingsValue = Settings{} fakeSettingsSource.SettingsErr = nil service, fs := buildService() fs.RemoveAllError = errors.New("fs-remove-all-error") err := service.InvalidateSettings() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fs-remove-all-error")) }) }) Describe("GetSettings", func() { var ( loadedSettings Settings service Service ) BeforeEach(func() { loadedSettings = Settings{AgentID: "some-agent-id"} }) JustBeforeEach(func() { fakeSettingsSource.SettingsValue = loadedSettings fakeSettingsSource.SettingsErr = nil service, _ = buildService() err := service.LoadSettings() Expect(err).NotTo(HaveOccurred()) }) Context("when there is are no dynamic networks", func() { It("returns settings without modifying any networks", func() { Expect(service.GetSettings()).To(Equal(loadedSettings)) }) It("does not try to determine default network", func() { _ = service.GetSettings() Expect(fakeDefaultNetworkResolver.GetDefaultNetworkCalled).To(BeFalse()) }) }) Context("when there is network that needs to be resolved (ip, netmask, or mac are not set)", func() { BeforeEach(func() { loadedSettings = Settings{ Networks: map[string]Network{ "fake-net1": Network{ IP: "fake-net1-ip", Netmask: "fake-net1-netmask", Mac: "fake-net1-mac", Gateway: "fake-net1-gateway", }, "fake-net2": Network{ Gateway: "fake-net2-gateway", DNS: []string{"fake-net2-dns"}, }, }, } }) Context("when default network can be retrieved", func() { BeforeEach(func() { fakeDefaultNetworkResolver.GetDefaultNetworkNetwork = Network{ IP: "fake-resolved-ip", Netmask: "fake-resolved-netmask", Gateway: "fake-resolved-gateway", } }) It("returns settings with resolved dynamic network ip, netmask, gateway and keeping everything else the same", func() { settings := service.GetSettings() Expect(settings).To(Equal(Settings{ Networks: map[string]Network{ "fake-net1": Network{ IP: "fake-net1-ip", Netmask: "fake-net1-netmask", Mac: "fake-net1-mac", Gateway: "fake-net1-gateway", }, "fake-net2": Network{ IP: "fake-resolved-ip", Netmask: "fake-resolved-netmask", Gateway: "fake-resolved-gateway", DNS: []string{"fake-net2-dns"}, Resolved: true, }, }, })) }) }) Context("when default network fails to be retrieved", func() { BeforeEach(func() { fakeDefaultNetworkResolver.GetDefaultNetworkErr = errors.New("fake-get-default-network-err") }) It("returns error", func() { settings := service.GetSettings() Expect(settings).To(Equal(loadedSettings)) }) }) }) }) }) }
func init() { Describe("bootstrap", func() { Describe("Run", func() { var ( platform *fakeplatform.FakePlatform dirProvider boshdir.Provider settingsSource *fakeinf.FakeSettingsSource settingsService *fakesettings.FakeSettingsService ) BeforeEach(func() { platform = fakeplatform.NewFakePlatform() dirProvider = boshdir.NewProvider("/var/vcap") settingsSource = &fakeinf.FakeSettingsSource{} settingsService = &fakesettings.FakeSettingsService{} }) bootstrap := func() error { logger := boshlog.NewLogger(boshlog.LevelNone) return NewBootstrap(platform, dirProvider, settingsService, logger).Run() } It("sets up runtime configuration", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupRuntimeConfigurationWasInvoked).To(BeTrue()) }) Describe("SSH tunnel setup for registry", func() { It("returns error without configuring ssh on the platform if getting public key fails", func() { settingsService.PublicKeyErr = errors.New("fake-get-public-key-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-public-key-err")) Expect(platform.SetupSSHCalled).To(BeFalse()) }) Context("when public key is not empty", func() { BeforeEach(func() { settingsService.PublicKey = "fake-public-key" }) It("gets the public key and sets up ssh via the platform", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupSSHPublicKey).To(Equal("fake-public-key")) Expect(platform.SetupSSHUsername).To(Equal("vcap")) }) It("returns error if configuring ssh on the platform fails", func() { platform.SetupSSHErr = errors.New("fake-setup-ssh-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-ssh-err")) }) }) Context("when public key key is empty", func() { BeforeEach(func() { settingsSource.PublicKey = "" }) It("gets the public key and does not setup SSH", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupSSHCalled).To(BeFalse()) }) }) }) It("sets up hostname", func() { settingsService.Settings.AgentID = "foo-bar-baz-123" err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupHostnameHostname).To(Equal("foo-bar-baz-123")) }) It("fetches initial settings", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(settingsService.SettingsWereLoaded).To(BeTrue()) }) It("returns error from loading initial settings", func() { settingsService.LoadSettingsError = errors.New("fake-load-error") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-load-error")) }) It("sets up networking", func() { networks := boshsettings.Networks{ "bosh": boshsettings.Network{}, } settingsService.Settings.Networks = networks err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupNetworkingNetworks).To(Equal(networks)) }) It("sets up ephemeral disk", func() { settingsService.Settings.Disks = boshsettings.Disks{ Ephemeral: "fake-ephemeral-disk-setting", } platform.GetEphemeralDiskPathRealPath = "/dev/sda" err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupEphemeralDiskWithPathDevicePath).To(Equal("/dev/sda")) Expect(platform.GetEphemeralDiskPathSettings).To(Equal(boshsettings.DiskSettings{ VolumeID: "fake-ephemeral-disk-setting", Path: "fake-ephemeral-disk-setting", })) }) It("returns error if setting ephemeral disk fails", func() { platform.SetupEphemeralDiskWithPathErr = errors.New("fake-setup-ephemeral-disk-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-ephemeral-disk-err")) }) It("sets up raw ephemeral disks if paths exist", func() { settingsService.Settings.Disks = boshsettings.Disks{ RawEphemeral: []boshsettings.DiskSettings{{Path: "/dev/xvdb"}, {Path: "/dev/xvdc"}}, } err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupRawEphemeralDisksCallCount).To(Equal(1)) Expect(len(platform.SetupRawEphemeralDisksDevices)).To(Equal(2)) Expect(platform.SetupRawEphemeralDisksDevices[0].Path).To(Equal("/dev/xvdb")) Expect(platform.SetupRawEphemeralDisksDevices[1].Path).To(Equal("/dev/xvdc")) }) It("returns error if setting raw ephemeral disks fails", func() { platform.SetupRawEphemeralDisksErr = errors.New("fake-setup-raw-ephemeral-disks-err") err := bootstrap() Expect(platform.SetupRawEphemeralDisksCallCount).To(Equal(1)) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-raw-ephemeral-disks-err")) }) It("sets up data dir", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupDataDirCalled).To(BeTrue()) }) It("returns error if set up of data dir fails", func() { platform.SetupDataDirErr = errors.New("fake-setup-data-dir-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-data-dir-err")) }) It("sets up tmp dir", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupTmpDirCalled).To(BeTrue()) }) It("returns error if set up of tmp dir fails", func() { platform.SetupTmpDirErr = errors.New("fake-setup-tmp-dir-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-tmp-dir-err")) }) It("mounts persistent disk", func() { settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "vol-123": map[string]interface{}{ "volume_id": "2", "path": "/dev/sdb", }, }, } err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.MountPersistentDiskSettings).To(Equal(boshsettings.DiskSettings{ ID: "vol-123", VolumeID: "2", Path: "/dev/sdb", })) Expect(platform.MountPersistentDiskMountPoint).To(Equal(dirProvider.StoreDir())) }) It("errors if there is more than one persistent disk", func() { settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "vol-123": "/dev/sdb", "vol-456": "/dev/sdc", }, } err := bootstrap() Expect(err).To(HaveOccurred()) }) It("does not try to mount when no persistent disk", func() { settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{}, } err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.MountPersistentDiskSettings).To(Equal(boshsettings.DiskSettings{})) Expect(platform.MountPersistentDiskMountPoint).To(Equal("")) }) It("grows the root filesystem", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupRootDiskCalledTimes).To(Equal(1)) }) It("returns an error if growing the root filesystem fails", func() { platform.SetupRootDiskError = errors.New("growfs failed") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(platform.SetupRootDiskCalledTimes).To(Equal(1)) Expect(err.Error()).To(ContainSubstring("growfs failed")) }) It("sets root and vcap passwords", func() { settingsService.Settings.Env.Bosh.Password = "******" settingsService.Settings.Env.Bosh.KeepRootPassword = false err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(2).To(Equal(len(platform.UserPasswords))) Expect("some-encrypted-password").To(Equal(platform.UserPasswords["root"])) Expect("some-encrypted-password").To(Equal(platform.UserPasswords["vcap"])) }) It("does not change root password if keep_root_password is set to true", func() { settingsService.Settings.Env.Bosh.Password = "******" settingsService.Settings.Env.Bosh.KeepRootPassword = true err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(1).To(Equal(len(platform.UserPasswords))) Expect("some-encrypted-password").ToNot(Equal(platform.UserPasswords["root"])) Expect("some-encrypted-password").To(Equal(platform.UserPasswords["vcap"])) }) It("does not set password if not provided", func() { settingsService.Settings.Env.Bosh.KeepRootPassword = false err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(0).To(Equal(len(platform.UserPasswords))) }) It("sets ntp", func() { settingsService.Settings.Ntp = []string{ "0.north-america.pool.ntp.org", "1.north-america.pool.ntp.org", } err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(2).To(Equal(len(platform.SetTimeWithNtpServersServers))) Expect("0.north-america.pool.ntp.org").To(Equal(platform.SetTimeWithNtpServersServers[0])) Expect("1.north-america.pool.ntp.org").To(Equal(platform.SetTimeWithNtpServersServers[1])) }) It("setups up monit user", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupMonitUserSetup).To(BeTrue()) }) It("starts monit", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.StartMonitStarted).To(BeTrue()) }) }) Describe("Network setup exercised by Run", func() { var ( settingsJSON string fs *fakesys.FakeFileSystem platform boshplatform.Platform boot Bootstrap defaultNetworkResolver boshsettings.DefaultNetworkResolver logger boshlog.Logger dirProvider boshdirs.Provider interfaceAddrsProvider *fakeip.FakeInterfaceAddressesProvider ) writeNetworkDevice := func(iface string, macAddress string, isPhysical bool) string { interfacePath := fmt.Sprintf("/sys/class/net/%s", iface) fs.WriteFile(interfacePath, []byte{}) if isPhysical { fs.WriteFile(fmt.Sprintf("/sys/class/net/%s/device", iface), []byte{}) } fs.WriteFileString(fmt.Sprintf("/sys/class/net/%s/address", iface), fmt.Sprintf("%s\n", macAddress)) return interfacePath } stubInterfaces := func(interfaces [][]string) { var interfacePaths []string for _, iface := range interfaces { interfaceName := iface[0] interfaceMAC := iface[1] interfaceType := iface[2] isPhysical := interfaceType == "physical" interfacePaths = append(interfacePaths, writeNetworkDevice(interfaceName, interfaceMAC, isPhysical)) } fs.SetGlob("/sys/class/net/*", interfacePaths) } BeforeEach(func() { fs = fakesys.NewFakeFileSystem() runner := fakesys.NewFakeCmdRunner() dirProvider = boshdirs.NewProvider("/var/vcap/bosh") linuxOptions := boshplatform.LinuxOptions{ CreatePartitionIfNoEphemeralDisk: true, } logger = boshlog.NewLogger(boshlog.LevelNone) diskManager := fakedisk.NewFakeDiskManager() diskManager.FakeMountsSearcher.SearchMountsMounts = []boshdisk.Mount{ {MountPoint: "/", PartitionPath: "rootfs"}, {MountPoint: "/", PartitionPath: "/dev/vda1"}, } // for the GrowRootFS call to findRootDevicePath runner.AddCmdResult( "readlink -f /dev/vda1", fakesys.FakeCmdResult{Stdout: "/dev/vda1"}, ) // for the createEphemeralPartitionsOnRootDevice call to findRootDevicePath runner.AddCmdResult( "readlink -f /dev/vda1", fakesys.FakeCmdResult{Stdout: "/dev/vda1"}, ) diskManager.FakeRootDevicePartitioner.GetDeviceSizeInBytesSizes["/dev/vda"] = 1024 * 1024 * 1024 udev := boshudev.NewConcreteUdevDevice(runner, logger) linuxCdrom := boshcdrom.NewLinuxCdrom("/dev/sr0", udev, runner) linuxCdutil := boshcdrom.NewCdUtil(dirProvider.SettingsDir(), fs, linuxCdrom, logger) compressor := boshcmd.NewTarballCompressor(runner, fs) copier := boshcmd.NewCpCopier(runner, fs, logger) sigarCollector := boshsigar.NewSigarStatsCollector(&sigar.ConcreteSigar{}) vitalsService := boshvitals.NewService(sigarCollector, dirProvider) ipResolver := boship.NewResolver(boship.NetworkInterfaceToAddrsFunc) arping := bosharp.NewArping(runner, fs, logger, boshplatform.ArpIterations, boshplatform.ArpIterationDelay, boshplatform.ArpInterfaceCheckDelay) interfaceConfigurationCreator := boshnet.NewInterfaceConfigurationCreator(logger) interfaceAddrsProvider = &fakeip.FakeInterfaceAddressesProvider{} interfaceAddressesValidator := boship.NewInterfaceAddressesValidator(interfaceAddrsProvider) dnsValidator := boshnet.NewDNSValidator(fs) fs.WriteFileString("/etc/resolv.conf", "8.8.8.8 4.4.4.4") ubuntuNetManager := boshnet.NewUbuntuNetManager(fs, runner, ipResolver, interfaceConfigurationCreator, interfaceAddressesValidator, dnsValidator, arping, logger) ubuntuCertManager := boshcert.NewUbuntuCertManager(fs, runner, 1, logger) monitRetryable := boshplatform.NewMonitRetryable(runner) monitRetryStrategy := boshretry.NewAttemptRetryStrategy(10, 1*time.Second, monitRetryable, logger) devicePathResolver := devicepathresolver.NewIdentityDevicePathResolver() routesSearcher := boshnet.NewCmdRoutesSearcher(runner) defaultNetworkResolver = boshnet.NewDefaultNetworkResolver(routesSearcher, ipResolver) state, err := boshplatform.NewBootstrapState(fs, "/tmp/agent_state.json") Expect(err).NotTo(HaveOccurred()) platform = boshplatform.NewLinuxPlatform( fs, runner, sigarCollector, compressor, copier, dirProvider, vitalsService, linuxCdutil, diskManager, ubuntuNetManager, ubuntuCertManager, monitRetryStrategy, devicePathResolver, 500*time.Millisecond, state, linuxOptions, logger, defaultNetworkResolver, ) }) JustBeforeEach(func() { settingsPath := filepath.Join("bosh", "settings.json") var settings boshsettings.Settings json.Unmarshal([]byte(settingsJSON), &settings) settingsSource := fakeinf.FakeSettingsSource{ PublicKey: "123", SettingsValue: settings, } settingsService := boshsettings.NewService( platform.GetFs(), settingsPath, settingsSource, platform, logger, ) boot = NewBootstrap( platform, dirProvider, settingsService, logger, ) }) Context("when a single network configuration is provided, with a MAC address", func() { BeforeEach(func() { settingsJSON = `{ "networks": { "netA": { "default": ["dns", "gateway"], "ip": "2.2.2.2", "dns": [ "8.8.8.8", "4.4.4.4" ], "netmask": "255.255.255.0", "gateway": "2.2.2.0", "mac": "aa:bb:cc" } } }` }) Context("and no physical network interfaces exist", func() { Context("and a single virtual network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"lo", "aa:bb:cc", "virtual"}}) }) It("raises an error", func() { err := boot.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Number of network settings '1' is greater than the number of network devices '0")) }) }) }) Context("and a single physical network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), } }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) Context("and extra physical network interfaces exist", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"eth1", "aa:bb:dd", "physical"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), } }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) Context("and extra virtual network interfaces exist", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"lo", "aa:bb:ee", "virtual"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), } }) It("succeeds", func() { err := boot.Run() Expect(err).ToNot(HaveOccurred()) }) }) }) Context("when a single network configuration is provided, without a MAC address", func() { BeforeEach(func() { settingsJSON = `{ "networks": { "netA": { "default": ["dns", "gateway"], "ip": "2.2.2.2", "dns": [ "8.8.8.8", "4.4.4.4" ], "netmask": "255.255.255.0", "gateway": "2.2.2.0" } } }` }) Context("and no physical network interfaces exist", func() { Context("and a single virtual network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"lo", "aa:bb:cc", "virtual"}}) }) It("raises an error", func() { err := boot.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Number of network settings '1' is greater than the number of network devices '0")) }) }) }) Context("and a single physical network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), } }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) Context("and extra physical network interfaces exist", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"eth1", "aa:bb:dd", "physical"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), } }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) Context("and an extra virtual network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"lo", "aa:bb:dd", "virtual"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), } }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) }) Context("when two network configurations are provided", func() { BeforeEach(func() { settingsJSON = `{ "networks": { "netA": { "default": ["dns", "gateway"], "ip": "2.2.2.2", "dns": [ "8.8.8.8", "4.4.4.4" ], "netmask": "255.255.255.0", "gateway": "2.2.2.0", "mac": "aa:bb:cc" }, "netB": { "default": ["dns", "gateway"], "ip": "3.3.3.3", "dns": [ "8.8.8.8", "4.4.4.4" ], "netmask": "255.255.255.0", "gateway": "3.3.3.0", "mac": "" } } }` }) Context("and a single physical network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}}) }) It("raises an error", func() { err := boot.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Number of network settings '2' is greater than the number of network devices '1")) }) }) Context("and two physical network interfaces with matching MAC addresses exist", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"eth1", "aa:bb:dd", "physical"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), boship.NewSimpleInterfaceAddress("eth1", "3.3.3.3"), } }) It("succeeds", func() { err := boot.Run() Expect(err).ToNot(HaveOccurred()) }) }) }) }) }) }
func init() { Describe("provider", func() { var ( platform *fakeplatform.FakePlatform client *fakemonit.FakeMonitClient logger boshlog.Logger dirProvider boshdir.Provider jobFailuresServerPort int handler *fakembus.FakeHandler provider Provider timeService clock.Clock ) BeforeEach(func() { platform = fakeplatform.NewFakePlatform() client = fakemonit.NewFakeMonitClient() logger = boshlog.NewLogger(boshlog.LevelNone) dirProvider = boshdir.NewProvider("/fake-base-dir") jobFailuresServerPort = 2825 handler = &fakembus.FakeHandler{} timeService = clock.NewClock() provider = NewProvider( platform, client, logger, dirProvider, handler, ) }) It("provides a monit job supervisor", func() { actualSupervisor, err := provider.Get("monit") Expect(err).ToNot(HaveOccurred()) expectedSupervisor := NewMonitJobSupervisor( platform.Fs, platform.Runner, client, logger, dirProvider, jobFailuresServerPort, MonitReloadOptions{ MaxTries: 3, MaxCheckTries: 6, DelayBetweenCheckTries: 5 * time.Second, }, timeService, ) Expect(actualSupervisor).To(Equal(expectedSupervisor)) }) It("provides a dummy job supervisor", func() { actualSupervisor, err := provider.Get("dummy") Expect(err).ToNot(HaveOccurred()) expectedSupervisor := NewDummyJobSupervisor() Expect(actualSupervisor).To(Equal(expectedSupervisor)) }) It("provides a dummy nats job supervisor", func() { actualSupervisor, err := provider.Get("dummy-nats") Expect(err).NotTo(HaveOccurred()) expectedSupervisor := NewDummyNatsJobSupervisor(handler) Expect(actualSupervisor).To(Equal(expectedSupervisor)) }) It("returns an error when the supervisor is not found", func() { _, err := provider.Get("does-not-exist") Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("does-not-exist could not be found")) }) }) }
func init() { Describe("asyncTaskService", func() { var ( uuidGen *fakeuuid.FakeGenerator service Service ) BeforeEach(func() { uuidGen = &fakeuuid.FakeGenerator{} service = NewAsyncTaskService(uuidGen, boshlog.NewLogger(boshlog.LevelNone)) }) Describe("StartTask", func() { startAndWaitForTaskCompletion := func(task Task) Task { service.StartTask(task) for task.State == StateRunning { time.Sleep(time.Nanosecond) task, _ = service.FindTaskWithID(task.ID) } return task } It("sets return value on a successful task", func() { runFunc := func() (interface{}, error) { return 123, nil } task, err := service.CreateTask(runFunc, nil, nil) Expect(err).ToNot(HaveOccurred()) task = startAndWaitForTaskCompletion(task) Expect(task.State).To(BeEquivalentTo(StateDone)) Expect(task.Value).To(Equal(123)) Expect(task.Error).To(BeNil()) }) It("sets task error on a failing task", func() { err := errors.New("fake-error") runFunc := func() (interface{}, error) { return nil, err } task, createErr := service.CreateTask(runFunc, nil, nil) Expect(createErr).ToNot(HaveOccurred()) task = startAndWaitForTaskCompletion(task) Expect(task.State).To(BeEquivalentTo(StateFailed)) Expect(task.Value).To(BeNil()) Expect(task.Error).To(Equal(err)) }) Describe("CreateTask", func() { It("can run task created with CreateTask which does not have end func", func() { ranFunc := false runFunc := func() (interface{}, error) { ranFunc = true; return nil, nil } task, err := service.CreateTask(runFunc, nil, nil) Expect(err).ToNot(HaveOccurred()) startAndWaitForTaskCompletion(task) Expect(ranFunc).To(BeTrue()) }) It("can run task created with CreateTask which has end func", func() { ranFunc := false runFunc := func() (interface{}, error) { ranFunc = true; return nil, nil } ranEndFunc := false endFunc := func(Task) { ranEndFunc = true } task, err := service.CreateTask(runFunc, nil, endFunc) Expect(err).ToNot(HaveOccurred()) startAndWaitForTaskCompletion(task) Expect(ranFunc).To(BeTrue()) Expect(ranEndFunc).To(BeTrue()) }) It("returns an error if generate uuid fails", func() { uuidGen.GenerateError = errors.New("fake-generate-uuid-error") _, err := service.CreateTask(nil, nil, nil) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-generate-uuid-error")) }) }) Describe("CreateTaskWithID", func() { It("can run task created with CreateTaskWithID which does not have end func", func() { ranFunc := false runFunc := func() (interface{}, error) { ranFunc = true; return nil, nil } task := service.CreateTaskWithID("fake-task-id", runFunc, nil, nil) startAndWaitForTaskCompletion(task) Expect(ranFunc).To(BeTrue()) }) It("can run task created with CreateTaskWithID which has end func", func() { ranFunc := false runFunc := func() (interface{}, error) { ranFunc = true; return nil, nil } ranEndFunc := false endFunc := func(Task) { ranEndFunc = true } task := service.CreateTaskWithID("fake-task-id", runFunc, nil, endFunc) startAndWaitForTaskCompletion(task) Expect(ranFunc).To(BeTrue()) Expect(ranEndFunc).To(BeTrue()) }) }) It("can process many tasks simultaneously", func() { taskFunc := func() (interface{}, error) { time.Sleep(10 * time.Millisecond) return nil, nil } ids := []string{} for id := 1; id < 200; id++ { idStr := fmt.Sprintf("%d", id) uuidGen.GeneratedUUID = idStr ids = append(ids, idStr) task, err := service.CreateTask(taskFunc, nil, nil) Expect(err).ToNot(HaveOccurred()) go service.StartTask(task) } for { allDone := true for _, id := range ids { task, _ := service.FindTaskWithID(id) if task.State != StateDone { allDone = false break } } if allDone { break } time.Sleep(200 * time.Millisecond) } }) }) Describe("CreateTask", func() { It("creates a task with auto-assigned id", func() { uuidGen.GeneratedUUID = "fake-uuid" runFuncCalled := false runFunc := func() (interface{}, error) { runFuncCalled = true return nil, nil } cancelFuncCalled := false cancelFunc := func(_ Task) error { cancelFuncCalled = true return nil } endFuncCalled := false endFunc := func(_ Task) { endFuncCalled = true } task, err := service.CreateTask(runFunc, cancelFunc, endFunc) Expect(err).ToNot(HaveOccurred()) Expect(task.ID).To(Equal("fake-uuid")) Expect(task.State).To(Equal(StateRunning)) task.Func() Expect(runFuncCalled).To(BeTrue()) task.CancelFunc(task) Expect(cancelFuncCalled).To(BeTrue()) task.EndFunc(task) Expect(endFuncCalled).To(BeTrue()) }) }) Describe("CreateTaskWithID", func() { It("creates a task with given id", func() { runFuncCalled := false runFunc := func() (interface{}, error) { runFuncCalled = true return nil, nil } cancelFuncCalled := false cancelFunc := func(_ Task) error { cancelFuncCalled = true return nil } endFuncCalled := false endFunc := func(_ Task) { endFuncCalled = true } task := service.CreateTaskWithID("fake-task-id", runFunc, cancelFunc, endFunc) Expect(task.ID).To(Equal("fake-task-id")) Expect(task.State).To(Equal(StateRunning)) task.Func() Expect(runFuncCalled).To(BeTrue()) task.CancelFunc(task) Expect(cancelFuncCalled).To(BeTrue()) task.EndFunc(task) Expect(endFuncCalled).To(BeTrue()) }) }) }) }
"github.com/cloudfoundry/bosh-utils/logger" "github.com/cloudfoundry/bosh-utils/system" fakesys "github.com/cloudfoundry/bosh-utils/system/fakes" ) const cert1 string = `-----BEGIN CERTIFICATE----- MIIEJDCCAwygAwIBAgIJAO+CqgiJnCgpMA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNV BAYTAkNBMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX qokoSBXzJCJTt2P681gyqBDr/hUYzqpoXUsOTRisScbEbaSv8hTiTeFJUMyNQAqn DtmvI8bXKxU= -----END CERTIFICATE-----` var _ = Describe("Certificate Management", func() { var log logger.Logger BeforeEach(func() { log = logger.NewLogger(logger.LevelNone) }) Describe("CertificateSplitting", func() { It("splits 2 back-to-back certificates", func() { certs := fmt.Sprintf("%s\n%s\n", cert1, cert1) result := cert.SplitCerts(certs) Expect(result[0]).To(Equal(cert1)) Expect(result[1]).To(Equal(cert1)) Expect(len(result)).To(Equal(2)) }) It("splits 2 back-to-back certificates without trailing newline", func() { certs := fmt.Sprintf("%s\n%s", cert1, cert1)
It("creates temp files under that root", func() { file, err := osFs.TempFile("some-file-prefix") Expect(err).ToNot(HaveOccurred()) Expect(file.Name()).To(HavePrefix(filepath.Join(testTempDir, "some-file-prefix"))) }) It("creates temp directories under that root", func() { dirName, err := osFs.TempDir("some-dir-prefix") Expect(err).ToNot(HaveOccurred()) Expect(dirName).To(HavePrefix(filepath.Join(testTempDir, "some-dir-prefix"))) }) }) Context("no temp root is set and was initialized as a strict temp root", func() { BeforeEach(func() { osFs = NewOsFileSystemWithStrictTempRoot(boshlog.NewLogger(boshlog.LevelNone)) }) It("should eror", func() { _, err := osFs.TempFile("some-prefix") Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("ChangeTempRoot")) _, err = osFs.TempDir("some-prefix") Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("ChangeTempRoot")) }) }) }) Describe("CopyFile", func() {
. "github.com/cloudfoundry/bosh-agent/infrastructure" boshsettings "github.com/cloudfoundry/bosh-agent/settings" bosherr "github.com/cloudfoundry/bosh-utils/errors" boshlog "github.com/cloudfoundry/bosh-utils/logger" fakesys "github.com/cloudfoundry/bosh-utils/system/fakes" ) var _ = Describe("FileMetadataService", func() { var ( fs *fakesys.FakeFileSystem metadataService MetadataService ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() logger := boshlog.NewLogger(boshlog.LevelNone) metadataService = NewFileMetadataService( "fake-metadata-file-path", "fake-userdata-file-path", "fake-settings-file-path", fs, logger, ) }) Describe("GetInstanceID", func() { Context("when metadata service file exists", func() { BeforeEach(func() { metadataContents := `{"instance-id":"fake-instance-id"}` fs.WriteFileString("fake-metadata-file-path", metadataContents) })
func rootDesc() { var mockCtrl *gomock.Controller BeforeEach(func() { mockCtrl = gomock.NewController(GinkgoT()) }) AfterEach(func() { mockCtrl.Finish() }) Describe("Run", func() { var ( command bicmd.Cmd fakeFs *fakesys.FakeFileSystem stdOut *gbytes.Buffer stdErr *gbytes.Buffer userInterface biui.UI sha1Calculator crypto.SHA1Calculator manifestSHA1 string mockDeployer *mock_deployment.MockDeployer mockInstaller *mock_install.MockInstaller mockInstallerFactory *mock_install.MockInstallerFactory mockReleaseExtractor *mock_release.MockExtractor releaseManager birel.Manager mockRegistryServerManager *mock_registry.MockServerManager mockRegistryServer *mock_registry.MockServer mockAgentClient *mock_agentclient.MockAgentClient mockAgentClientFactory *mock_httpagent.MockAgentClientFactory mockCloudFactory *mock_cloud.MockFactory fakeCPIRelease *fakebirel.FakeRelease logger boshlog.Logger mockBlobstoreFactory *mock_blobstore.MockFactory mockBlobstore *mock_blobstore.MockBlobstore mockVMManagerFactory *mock_vm.MockManagerFactory fakeVMManager *fakebivm.FakeManager fakeStemcellExtractor *fakebistemcell.FakeExtractor mockStemcellManager *mock_stemcell.MockManager fakeStemcellManagerFactory *fakebistemcell.FakeManagerFactory fakeReleaseSetParser *fakebirelsetmanifest.FakeParser fakeInstallationParser *fakebiinstallmanifest.FakeParser fakeDeploymentParser *fakebideplmanifest.FakeParser mockLegacyDeploymentStateMigrator *mock_config.MockLegacyDeploymentStateMigrator setupDeploymentStateService biconfig.DeploymentStateService fakeDeploymentValidator *fakebideplval.FakeValidator directorID = "generated-director-uuid" fakeUUIDGenerator *fakeuuid.FakeGenerator configUUIDGenerator *fakeuuid.FakeGenerator fakeStage *fakebiui.FakeStage deploymentManifestPath string deploymentStatePath string cpiReleaseTarballPath string stemcellTarballPath string extractedStemcell bistemcell.ExtractedStemcell expectDeploy *gomock.Call mbusURL = "http://*****:*****@fake-mbus-endpoint" releaseSetManifest birelsetmanifest.Manifest boshDeploymentManifest bideplmanifest.Manifest installationManifest biinstallmanifest.Manifest cloud bicloud.Cloud cloudStemcell bistemcell.CloudStemcell expectLegacyMigrate *gomock.Call expectStemcellUpload *gomock.Call expectStemcellDeleteUnused *gomock.Call expectCPIReleaseExtract *gomock.Call expectInstall *gomock.Call expectNewCloud *gomock.Call ) BeforeEach(func() { logger = boshlog.NewLogger(boshlog.LevelNone) stdOut = gbytes.NewBuffer() stdErr = gbytes.NewBuffer() userInterface = biui.NewWriterUI(stdOut, stdErr, logger) fakeFs = fakesys.NewFakeFileSystem() fakeFs.EnableStrictTempRootBehavior() deploymentManifestPath = "/path/to/manifest.yml" deploymentStatePath = "/path/to/manifest-state.json" fakeFs.RegisterOpenFile(deploymentManifestPath, &fakesys.FakeFile{ Stats: &fakesys.FakeFileStats{FileType: fakesys.FakeFileTypeFile}, }) fakeFs.WriteFileString(deploymentManifestPath, "") mockDeployer = mock_deployment.NewMockDeployer(mockCtrl) mockInstaller = mock_install.NewMockInstaller(mockCtrl) mockInstallerFactory = mock_install.NewMockInstallerFactory(mockCtrl) mockReleaseExtractor = mock_release.NewMockExtractor(mockCtrl) releaseManager = birel.NewManager(logger) mockRegistryServerManager = mock_registry.NewMockServerManager(mockCtrl) mockRegistryServer = mock_registry.NewMockServer(mockCtrl) mockAgentClientFactory = mock_httpagent.NewMockAgentClientFactory(mockCtrl) mockAgentClient = mock_agentclient.NewMockAgentClient(mockCtrl) mockAgentClientFactory.EXPECT().NewAgentClient(gomock.Any(), gomock.Any()).Return(mockAgentClient).AnyTimes() mockCloudFactory = mock_cloud.NewMockFactory(mockCtrl) mockBlobstoreFactory = mock_blobstore.NewMockFactory(mockCtrl) mockBlobstore = mock_blobstore.NewMockBlobstore(mockCtrl) mockBlobstoreFactory.EXPECT().Create(mbusURL, gomock.Any()).Return(mockBlobstore, nil).AnyTimes() mockVMManagerFactory = mock_vm.NewMockManagerFactory(mockCtrl) fakeVMManager = fakebivm.NewFakeManager() mockVMManagerFactory.EXPECT().NewManager(gomock.Any(), mockAgentClient).Return(fakeVMManager).AnyTimes() fakeStemcellExtractor = fakebistemcell.NewFakeExtractor() mockStemcellManager = mock_stemcell.NewMockManager(mockCtrl) fakeStemcellManagerFactory = fakebistemcell.NewFakeManagerFactory() fakeReleaseSetParser = fakebirelsetmanifest.NewFakeParser() fakeInstallationParser = fakebiinstallmanifest.NewFakeParser() fakeDeploymentParser = fakebideplmanifest.NewFakeParser() mockLegacyDeploymentStateMigrator = mock_config.NewMockLegacyDeploymentStateMigrator(mockCtrl) configUUIDGenerator = &fakeuuid.FakeGenerator{} configUUIDGenerator.GeneratedUUID = directorID setupDeploymentStateService = biconfig.NewFileSystemDeploymentStateService(fakeFs, configUUIDGenerator, logger, biconfig.DeploymentStatePath(deploymentManifestPath)) fakeDeploymentValidator = fakebideplval.NewFakeValidator() fakeStage = fakebiui.NewFakeStage() sha1Calculator = crypto.NewSha1Calculator(fakeFs) fakeUUIDGenerator = &fakeuuid.FakeGenerator{} var err error manifestSHA1, err = sha1Calculator.Calculate(deploymentManifestPath) Expect(err).ToNot(HaveOccurred()) cpiReleaseTarballPath = "/release/tarball/path" stemcellTarballPath = "/stemcell/tarball/path" extractedStemcell = bistemcell.NewExtractedStemcell( bistemcell.Manifest{ ImagePath: "/stemcell/image/path", Name: "fake-stemcell-name", Version: "fake-stemcell-version", SHA1: "fake-stemcell-sha1", CloudProperties: biproperty.Map{}, OS: "ubuntu-trusty", }, "fake-extracted-path", fakeFs, ) // create input files fakeFs.WriteFileString(cpiReleaseTarballPath, "") fakeFs.WriteFileString(stemcellTarballPath, "") // deployment exists fakeFs.WriteFileString(deploymentManifestPath, "") // deployment is valid fakeDeploymentValidator.SetValidateBehavior([]fakebideplval.ValidateOutput{ {Err: nil}, }) fakeDeploymentValidator.SetValidateReleaseJobsBehavior([]fakebideplval.ValidateReleaseJobsOutput{ {Err: nil}, }) // stemcell exists fakeFs.WriteFile(stemcellTarballPath, []byte{}) releaseSetManifest = birelsetmanifest.Manifest{ Releases: []birelmanifest.ReleaseRef{ { Name: "fake-cpi-release-name", URL: "file://" + cpiReleaseTarballPath, }, }, } // parsed CPI deployment manifest installationManifest = biinstallmanifest.Manifest{ Template: biinstallmanifest.ReleaseJobRef{ Name: "fake-cpi-release-job-name", Release: "fake-cpi-release-name", }, Mbus: mbusURL, } // parsed BOSH deployment manifest boshDeploymentManifest = bideplmanifest.Manifest{ Name: "fake-deployment-name", Jobs: []bideplmanifest.Job{ { Name: "fake-job-name", }, }, ResourcePools: []bideplmanifest.ResourcePool{ { Stemcell: bideplmanifest.StemcellRef{ URL: "file://" + stemcellTarballPath, }, }, }, } fakeDeploymentParser.ParseManifest = boshDeploymentManifest // parsed/extracted CPI release fakeCPIRelease = fakebirel.NewFakeRelease() fakeCPIRelease.ReleaseName = "fake-cpi-release-name" fakeCPIRelease.ReleaseVersion = "1.0" fakeCPIRelease.ReleaseIsCompiled = false fakeCPIRelease.ReleaseJobs = []bireljob.Job{ { Name: "fake-cpi-release-job-name", Templates: map[string]string{ "templates/cpi.erb": "bin/cpi", }, }, } cloud = bicloud.NewCloud(fakebicloud.NewFakeCPICmdRunner(), "fake-director-id", logger) cloudStemcell = fakebistemcell.NewFakeCloudStemcell("fake-stemcell-cid", "fake-stemcell-name", "fake-stemcell-version") }) JustBeforeEach(func() { doGet := func(deploymentManifestPath string) (bicmd.DeploymentPreparer, error) { deploymentStateService := biconfig.NewFileSystemDeploymentStateService(fakeFs, configUUIDGenerator, logger, biconfig.DeploymentStatePath(deploymentManifestPath)) deploymentRepo := biconfig.NewDeploymentRepo(deploymentStateService) releaseRepo := biconfig.NewReleaseRepo(deploymentStateService, fakeUUIDGenerator) stemcellRepo := biconfig.NewStemcellRepo(deploymentStateService, fakeUUIDGenerator) deploymentRecord := deployment.NewRecord(deploymentRepo, releaseRepo, stemcellRepo, sha1Calculator) fakeHTTPClient := fakebihttpclient.NewFakeHTTPClient() tarballCache := bitarball.NewCache("fake-base-path", fakeFs, logger) tarballProvider := bitarball.NewProvider(tarballCache, fakeFs, fakeHTTPClient, sha1Calculator, 1, 0, logger) cpiInstaller := bicpirel.CpiInstaller{ ReleaseManager: releaseManager, InstallerFactory: mockInstallerFactory, Validator: bicpirel.NewValidator(), } releaseFetcher := birel.NewFetcher(tarballProvider, mockReleaseExtractor, releaseManager) stemcellFetcher := bistemcell.Fetcher{ TarballProvider: tarballProvider, StemcellExtractor: fakeStemcellExtractor, } releaseSetAndInstallationManifestParser := bicmd.ReleaseSetAndInstallationManifestParser{ ReleaseSetParser: fakeReleaseSetParser, InstallationParser: fakeInstallationParser, } deploymentManifestParser := bicmd.DeploymentManifestParser{ DeploymentParser: fakeDeploymentParser, DeploymentValidator: fakeDeploymentValidator, ReleaseManager: releaseManager, } fakeInstallationUUIDGenerator := &fakeuuid.FakeGenerator{} fakeInstallationUUIDGenerator.GeneratedUUID = "fake-installation-id" targetProvider := biinstall.NewTargetProvider( deploymentStateService, fakeInstallationUUIDGenerator, filepath.Join("fake-install-dir"), ) tempRootConfigurator := bicmd.NewTempRootConfigurator(fakeFs) return bicmd.NewDeploymentPreparer( userInterface, logger, "deployCmd", deploymentStateService, mockLegacyDeploymentStateMigrator, releaseManager, deploymentRecord, mockCloudFactory, fakeStemcellManagerFactory, mockAgentClientFactory, mockVMManagerFactory, mockBlobstoreFactory, mockDeployer, deploymentManifestPath, cpiInstaller, releaseFetcher, stemcellFetcher, releaseSetAndInstallationManifestParser, deploymentManifestParser, tempRootConfigurator, targetProvider, ), nil } command = bicmd.NewDeployCmd(userInterface, fakeFs, logger, doGet) expectLegacyMigrate = mockLegacyDeploymentStateMigrator.EXPECT().MigrateIfExists("/path/to/bosh-deployments.yml").AnyTimes() fakeStemcellExtractor.SetExtractBehavior(stemcellTarballPath, extractedStemcell, nil) fakeStemcellManagerFactory.SetNewManagerBehavior(cloud, mockStemcellManager) expectStemcellUpload = mockStemcellManager.EXPECT().Upload(extractedStemcell, fakeStage).Return(cloudStemcell, nil).AnyTimes() expectStemcellDeleteUnused = mockStemcellManager.EXPECT().DeleteUnused(fakeStage).AnyTimes() fakeReleaseSetParser.ParseManifest = releaseSetManifest fakeDeploymentParser.ParseManifest = boshDeploymentManifest fakeInstallationParser.ParseManifest = installationManifest installationPath := filepath.Join("fake-install-dir", "fake-installation-id") target := biinstall.NewTarget(installationPath) installedJob := biinstall.NewInstalledJob( biinstall.RenderedJobRef{ Name: "fake-cpi-release-job-name", }, filepath.Join(target.JobsPath(), "fake-cpi-release-job-name"), ) mockInstallerFactory.EXPECT().NewInstaller(target).Return(mockInstaller).AnyTimes() installation := biinstall.NewInstallation(target, installedJob, installationManifest, mockRegistryServerManager) expectInstall = mockInstaller.EXPECT().Install(installationManifest, gomock.Any()).Do(func(_ interface{}, stage biui.Stage) { Expect(fakeStage.SubStages).To(ContainElement(stage)) }).Return(installation, nil).AnyTimes() mockInstaller.EXPECT().Cleanup(installation).AnyTimes() mockDeployment := mock_deployment.NewMockDeployment(mockCtrl) expectDeploy = mockDeployer.EXPECT().Deploy( cloud, boshDeploymentManifest, cloudStemcell, installationManifest.Registry, fakeVMManager, mockBlobstore, gomock.Any(), ).Do(func(_, _, _, _, _, _ interface{}, stage biui.Stage) { Expect(fakeStage.SubStages).To(ContainElement(stage)) }).Return(mockDeployment, nil).AnyTimes() expectCPIReleaseExtract = mockReleaseExtractor.EXPECT().Extract(cpiReleaseTarballPath).Return(fakeCPIRelease, nil).AnyTimes() expectNewCloud = mockCloudFactory.EXPECT().NewCloud(installation, directorID).Return(cloud, nil).AnyTimes() }) It("prints the deployment manifest and state file", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(stdOut).To(gbytes.Say("Deployment manifest: '/path/to/manifest.yml'")) Expect(stdOut).To(gbytes.Say("Deployment state: '/path/to/manifest-state.json'")) }) It("does not migrate the legacy bosh-deployments.yml if manifest-state.json exists", func() { err := fakeFs.WriteFileString(deploymentStatePath, "{}") Expect(err).ToNot(HaveOccurred()) expectLegacyMigrate.Times(0) err = command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeInstallationParser.ParsePath).To(Equal(deploymentManifestPath)) }) It("migrates the legacy bosh-deployments.yml if manifest-state.json does not exist", func() { err := fakeFs.RemoveAll(deploymentStatePath) Expect(err).ToNot(HaveOccurred()) expectLegacyMigrate.Return(true, nil).Times(1) err = command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeInstallationParser.ParsePath).To(Equal(deploymentManifestPath)) Expect(stdOut).To(gbytes.Say("Deployment manifest: '/path/to/manifest.yml'")) Expect(stdOut).To(gbytes.Say("Deployment state: '/path/to/manifest-state.json'")) Expect(stdOut).To(gbytes.Say("Migrated legacy deployments file: '/path/to/bosh-deployments.yml'")) }) It("sets the temp root", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeFs.TempRootPath).To(Equal("fake-install-dir/fake-installation-id/tmp")) }) Context("when setting the temp root fails", func() { It("returns an error", func() { fakeFs.ChangeTempRootErr = errors.New("fake ChangeTempRootErr") err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(Equal("Setting temp root: fake ChangeTempRootErr")) }) }) It("parses the installation manifest", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeInstallationParser.ParsePath).To(Equal(deploymentManifestPath)) }) It("parses the deployment manifest", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeDeploymentParser.ParsePath).To(Equal(deploymentManifestPath)) }) It("validates bosh deployment manifest", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeDeploymentValidator.ValidateInputs).To(Equal([]fakebideplval.ValidateInput{ {Manifest: boshDeploymentManifest, ReleaseSetManifest: releaseSetManifest}, })) }) It("validates jobs in manifest refer to job in releases", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeDeploymentValidator.ValidateReleaseJobsInputs).To(Equal([]fakebideplval.ValidateReleaseJobsInput{ {Manifest: boshDeploymentManifest, ReleaseManager: releaseManager}, })) }) It("logs validating stages", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeStage.PerformCalls[0]).To(Equal(&fakebiui.PerformCall{ Name: "validating", Stage: &fakebiui.FakeStage{ PerformCalls: []*fakebiui.PerformCall{ {Name: "Validating release 'fake-cpi-release-name'"}, {Name: "Validating cpi release"}, {Name: "Validating deployment manifest"}, {Name: "Validating stemcell"}, }, }, })) }) It("extracts CPI release tarball", func() { expectCPIReleaseExtract.Times(1) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) }) It("installs the CPI locally", func() { expectInstall.Times(1) expectNewCloud.Times(1) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) }) It("adds a new 'installing CPI' event logger stage", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeStage.PerformCalls[1]).To(Equal(&fakebiui.PerformCall{ Name: "installing CPI", Stage: &fakebiui.FakeStage{}, // mock installer doesn't add sub-stages })) }) It("adds a new 'Starting registry' event logger stage", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeStage.PerformCalls[2]).To(Equal(&fakebiui.PerformCall{ Name: "Starting registry", })) }) Context("when the registry is configured", func() { BeforeEach(func() { installationManifest.Registry = biinstallmanifest.Registry{ Username: "******", Password: "******", Host: "fake-host", Port: 123, } }) It("starts & stops the registry", func() { mockRegistryServerManager.EXPECT().Start("fake-username", "fake-password", "fake-host", 123).Return(mockRegistryServer, nil) mockRegistryServer.EXPECT().Stop() err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) }) }) It("deletes the extracted CPI release", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeCPIRelease.DeleteCalled).To(BeTrue()) }) It("extracts the stemcell", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeStemcellExtractor.ExtractInputs).To(Equal([]fakebistemcell.ExtractInput{ {TarballPath: stemcellTarballPath}, })) }) It("uploads the stemcell", func() { expectStemcellUpload.Times(1) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).ToNot(HaveOccurred()) }) It("adds a new 'deploying' event logger stage", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeStage.PerformCalls[3]).To(Equal(&fakebiui.PerformCall{ Name: "deploying", Stage: &fakebiui.FakeStage{}, // mock deployer doesn't add sub-stages })) }) It("deploys", func() { expectDeploy.Times(1) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) }) It("updates the deployment record", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) deploymentState, err := setupDeploymentStateService.Load() Expect(err).ToNot(HaveOccurred()) Expect(deploymentState.CurrentManifestSHA1).To(Equal(manifestSHA1)) Expect(deploymentState.Releases).To(Equal([]biconfig.ReleaseRecord{ { ID: "fake-uuid-0", Name: fakeCPIRelease.Name(), Version: fakeCPIRelease.Version(), }, })) }) It("deletes unused stemcells", func() { expectStemcellDeleteUnused.Times(1) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) }) Context("when deployment has not changed", func() { JustBeforeEach(func() { previousDeploymentState := biconfig.DeploymentState{ DirectorID: directorID, CurrentReleaseIDs: []string{"my-release-id-1"}, Releases: []biconfig.ReleaseRecord{{ ID: "my-release-id-1", Name: fakeCPIRelease.Name(), Version: fakeCPIRelease.Version(), }}, CurrentStemcellID: "my-stemcellRecordID", Stemcells: []biconfig.StemcellRecord{{ ID: "my-stemcellRecordID", Name: cloudStemcell.Name(), Version: cloudStemcell.Version(), }}, CurrentManifestSHA1: manifestSHA1, } err := setupDeploymentStateService.Save(previousDeploymentState) Expect(err).ToNot(HaveOccurred()) }) It("skips deploy", func() { expectDeploy.Times(0) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(stdOut).To(gbytes.Say("No deployment, stemcell or release changes. Skipping deploy.")) }) }) Context("when parsing the cpi deployment manifest fails", func() { BeforeEach(func() { fakeDeploymentParser.ParseErr = bosherr.Error("fake-parse-error") }) It("returns error", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Parsing deployment manifest")) Expect(err.Error()).To(ContainSubstring("fake-parse-error")) Expect(fakeDeploymentParser.ParsePath).To(Equal(deploymentManifestPath)) }) }) Context("when the cpi release does not contain a 'cpi' job", func() { BeforeEach(func() { fakeCPIRelease.ReleaseJobs = []bireljob.Job{ { Name: "not-cpi", }, } }) It("returns error", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(Equal("Invalid CPI release 'fake-cpi-release-name': CPI release must contain specified job 'fake-cpi-release-job-name'")) }) }) Context("when multiple releases are given", func() { var ( otherReleaseTarballPath string fakeOtherRelease *fakebirel.FakeRelease expectOtherReleaseExtract *gomock.Call ) BeforeEach(func() { otherReleaseTarballPath = "/path/to/other-release.tgz" fakeFs.WriteFileString(otherReleaseTarballPath, "") fakeOtherRelease = fakebirel.New("other-release", "1234") fakeOtherRelease.ReleaseJobs = []bireljob.Job{{Name: "not-cpi"}} expectOtherReleaseExtract = mockReleaseExtractor.EXPECT().Extract( otherReleaseTarballPath, ).Return(fakeOtherRelease, nil).AnyTimes() releaseSetManifest = birelsetmanifest.Manifest{ Releases: []birelmanifest.ReleaseRef{ { Name: "fake-cpi-release-name", URL: "file://" + cpiReleaseTarballPath, }, { Name: "other-release", URL: "file://" + otherReleaseTarballPath, }, }, } }) It("extracts all the release tarballs", func() { expectCPIReleaseExtract.Times(1) expectOtherReleaseExtract.Times(1) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) }) It("installs the CPI release locally", func() { expectInstall.Times(1) expectNewCloud.Times(1) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) }) It("updates the deployment record", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) deploymentState, err := setupDeploymentStateService.Load() Expect(err).ToNot(HaveOccurred()) Expect(deploymentState.CurrentManifestSHA1).To(Equal(manifestSHA1)) Expect(deploymentState.Releases).To(Equal([]biconfig.ReleaseRecord{ { ID: "fake-uuid-0", Name: fakeCPIRelease.Name(), Version: fakeCPIRelease.Version(), }, { ID: "fake-uuid-1", Name: fakeOtherRelease.Name(), Version: fakeOtherRelease.Version(), }, })) }) Context("when one of the releases in the deployment has changed", func() { JustBeforeEach(func() { olderReleaseVersion := "1233" Expect(fakeOtherRelease.Version()).ToNot(Equal(olderReleaseVersion)) previousDeploymentState := biconfig.DeploymentState{ DirectorID: directorID, CurrentReleaseIDs: []string{"existing-release-id-1", "existing-release-id-2"}, Releases: []biconfig.ReleaseRecord{ { ID: "existing-release-id-1", Name: fakeCPIRelease.Name(), Version: fakeCPIRelease.Version(), }, { ID: "existing-release-id-2", Name: fakeOtherRelease.Name(), Version: olderReleaseVersion, }, }, CurrentStemcellID: "my-stemcellRecordID", Stemcells: []biconfig.StemcellRecord{{ ID: "my-stemcellRecordID", Name: cloudStemcell.Name(), Version: cloudStemcell.Version(), }}, CurrentManifestSHA1: manifestSHA1, } err := setupDeploymentStateService.Save(previousDeploymentState) Expect(err).ToNot(HaveOccurred()) }) It("updates the deployment record, clearing out unused releases", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) deploymentState, err := setupDeploymentStateService.Load() Expect(err).ToNot(HaveOccurred()) Expect(deploymentState.CurrentManifestSHA1).To(Equal(manifestSHA1)) keys := []string{} ids := []string{} for _, releaseRecord := range deploymentState.Releases { keys = append(keys, fmt.Sprintf("%s-%s", releaseRecord.Name, releaseRecord.Version)) ids = append(ids, releaseRecord.ID) } Expect(deploymentState.CurrentReleaseIDs).To(ConsistOf(ids)) Expect(keys).To(ConsistOf([]string{ fmt.Sprintf("%s-%s", fakeCPIRelease.Name(), fakeCPIRelease.Version()), fmt.Sprintf("%s-%s", fakeOtherRelease.Name(), fakeOtherRelease.Version()), })) }) }) Context("when the deployment has not changed", func() { JustBeforeEach(func() { previousDeploymentState := biconfig.DeploymentState{ DirectorID: directorID, CurrentReleaseIDs: []string{"my-release-id-1", "my-release-id-2"}, Releases: []biconfig.ReleaseRecord{ { ID: "my-release-id-1", Name: fakeCPIRelease.Name(), Version: fakeCPIRelease.Version(), }, { ID: "my-release-id-2", Name: fakeOtherRelease.Name(), Version: fakeOtherRelease.Version(), }, }, CurrentStemcellID: "my-stemcellRecordID", Stemcells: []biconfig.StemcellRecord{{ ID: "my-stemcellRecordID", Name: cloudStemcell.Name(), Version: cloudStemcell.Version(), }}, CurrentManifestSHA1: manifestSHA1, } err := setupDeploymentStateService.Save(previousDeploymentState) Expect(err).ToNot(HaveOccurred()) }) It("skips deploy", func() { expectDeploy.Times(0) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(stdOut).To(gbytes.Say("No deployment, stemcell or release changes. Skipping deploy.")) }) }) }) Context("when release name does not match the name in release tarball", func() { BeforeEach(func() { releaseSetManifest.Releases = []birelmanifest.ReleaseRef{ { Name: "fake-other-cpi-release-name", URL: "file://" + cpiReleaseTarballPath, }, } }) It("returns an error", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Release name 'fake-other-cpi-release-name' does not match the name in release tarball 'fake-cpi-release-name'")) }) }) Context("When the stemcell tarball does not exist", func() { JustBeforeEach(func() { fakeStemcellExtractor.SetExtractBehavior(stemcellTarballPath, extractedStemcell, errors.New("no-stemcell-there")) }) It("returns error", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("no-stemcell-there")) performCall := fakeStage.PerformCalls[0].Stage.PerformCalls[3] Expect(performCall.Name).To(Equal("Validating stemcell")) Expect(performCall.Error.Error()).To(ContainSubstring("no-stemcell-there")) }) }) Context("when release file does not exist", func() { BeforeEach(func() { mockReleaseExtractor.EXPECT().Extract(cpiReleaseTarballPath).Return(nil, errors.New("not there")) }) It("returns error", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("not there")) performCall := fakeStage.PerformCalls[0].Stage.PerformCalls[0] Expect(performCall.Name).To(Equal("Validating release 'fake-cpi-release-name'")) Expect(performCall.Error.Error()).To(ContainSubstring("not there")) }) }) Context("when the deployment state file does not exist", func() { BeforeEach(func() { fakeFs.RemoveAll(deploymentStatePath) }) It("creates a deployment state", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).ToNot(HaveOccurred()) deploymentState, err := setupDeploymentStateService.Load() Expect(err).ToNot(HaveOccurred()) Expect(deploymentState.DirectorID).To(Equal(directorID)) }) }) It("returns err when the deployment manifest does not exist", func() { fakeFs.RemoveAll(deploymentManifestPath) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Deployment manifest does not exist at '/path/to/manifest.yml'")) Expect(stdErr).To(gbytes.Say("Deployment '/path/to/manifest.yml' does not exist")) }) Context("when the deployment manifest is invalid", func() { BeforeEach(func() { fakeDeploymentValidator.SetValidateBehavior([]fakebideplval.ValidateOutput{ {Err: bosherr.Error("fake-deployment-validation-error")}, }) }) It("returns err", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-deployment-validation-error")) }) It("logs the failed event log", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) performCall := fakeStage.PerformCalls[0].Stage.PerformCalls[2] Expect(performCall.Name).To(Equal("Validating deployment manifest")) Expect(performCall.Error.Error()).To(Equal("Validating deployment manifest: fake-deployment-validation-error")) }) }) Context("when validating jobs fails", func() { BeforeEach(func() { fakeDeploymentValidator.SetValidateReleaseJobsBehavior([]fakebideplval.ValidateReleaseJobsOutput{ {Err: bosherr.Error("fake-jobs-validation-error")}, }) }) It("returns err", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-jobs-validation-error")) }) It("logs the failed event log", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) performCall := fakeStage.PerformCalls[0].Stage.PerformCalls[2] Expect(performCall.Name).To(Equal("Validating deployment manifest")) Expect(performCall.Error.Error()).To(Equal("Validating deployment jobs refer to jobs in release: fake-jobs-validation-error")) }) }) It("returns err when number of arguments is not equal 1", func() { err := command.Run(fakeStage, []string{}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Invalid usage")) err = command.Run(fakeStage, []string{"1", "2"}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Invalid usage")) }) Context("when uploading stemcell fails", func() { JustBeforeEach(func() { expectStemcellUpload.Return(nil, bosherr.Error("fake-upload-error")) }) It("returns an error", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-upload-error")) }) }) Context("when deploy fails", func() { BeforeEach(func() { mockDeployer.EXPECT().Deploy( cloud, boshDeploymentManifest, cloudStemcell, installationManifest.Registry, fakeVMManager, mockBlobstore, gomock.Any(), ).Return(nil, errors.New("fake-deploy-error")).AnyTimes() previousDeploymentState := biconfig.DeploymentState{ CurrentReleaseIDs: []string{"my-release-id-1"}, Releases: []biconfig.ReleaseRecord{{ ID: "my-release-id-1", Name: fakeCPIRelease.Name(), Version: fakeCPIRelease.Version(), }}, CurrentManifestSHA1: "fake-manifest-sha", } setupDeploymentStateService.Save(previousDeploymentState) }) It("clears the deployment record", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-deploy-error")) deploymentState, err := setupDeploymentStateService.Load() Expect(err).ToNot(HaveOccurred()) Expect(deploymentState.CurrentManifestSHA1).To(Equal("")) Expect(deploymentState.Releases).To(Equal([]biconfig.ReleaseRecord{})) Expect(deploymentState.CurrentReleaseIDs).To(Equal([]string{})) }) }) Context("when compiled releases are being used", func() { var ( otherReleaseTarballPath string fakeOtherRelease *fakebirel.FakeRelease expectOtherReleaseExtract *gomock.Call ) BeforeEach(func() { otherReleaseTarballPath = "/path/to/other-release.tgz" fakeFs.WriteFileString(otherReleaseTarballPath, "") fakeOtherRelease = fakebirel.New("other-release", "1234") fakeOtherRelease.ReleaseIsCompiled = true fakeOtherRelease.ReleaseJobs = []bireljob.Job{{Name: "not-cpi"}} fakeOtherRelease.ReleasePackages = []*bipkg.Package{ { Stemcell: "ubuntu-trusty/fake-stemcell-version", }, } expectOtherReleaseExtract = mockReleaseExtractor.EXPECT().Extract( otherReleaseTarballPath, ).Return(fakeOtherRelease, nil).AnyTimes() releaseSetManifest = birelsetmanifest.Manifest{ Releases: []birelmanifest.ReleaseRef{ { Name: "fake-cpi-release-name", URL: "file://" + cpiReleaseTarballPath, }, { Name: "other-release", URL: "file://" + otherReleaseTarballPath, }, }, } boshDeploymentManifest = bideplmanifest.Manifest{ Name: "fake-deployment-name", Jobs: []bideplmanifest.Job{ { Name: "fake-job-name", Templates: []bideplmanifest.ReleaseJobRef{ { Release: "other-release", }, }, }, }, ResourcePools: []bideplmanifest.ResourcePool{ { Stemcell: bideplmanifest.StemcellRef{ URL: "file://" + stemcellTarballPath, }, }, }, } }) It("extracts the compiled release tarball", func() { expectOtherReleaseExtract.Times(1) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) }) It("parse compiled releases correctly", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).ToNot(HaveOccurred()) }) It("returns error if compiled package stemcell does not match the deployment stemcell", func() { fakeOtherRelease.ReleasePackages = []*bipkg.Package{ { Stemcell: "ubuntu-trusty/wrong-version", }, } err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("OS/Version mismatch between deployment stemcell and compiled package stemcell for release 'other-release'")) }) It("returns error if CPI release is compiled", func() { fakeCPIRelease.ReleaseIsCompiled = true err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("CPI is not allowed to be a compiled release. The provided CPI release 'fake-cpi-release-name' is compiled")) }) }) }) }