Esempio n. 1
0
			usermod := []string{"usermod", "-G", "group1,group2,group3", "foo-user"}
			Expect(cmdRunner.RunCommands[0]).To(Equal(usermod))
		})
	})

	Describe("DeleteEphemeralUsersMatching", func() {
		It("deletes users with prefix and regex", func() {
			passwdFile := `bosh_foo:...
bosh_bar:...
foo:...
bar:...
foobar:...
bosh_foobar:...`

			fs.WriteFileString("/etc/passwd", passwdFile)

			err := platform.DeleteEphemeralUsersMatching("bar$")
			Expect(err).NotTo(HaveOccurred())
			Expect(len(cmdRunner.RunCommands)).To(Equal(2))
			Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"userdel", "-r", "bosh_bar"}))
			Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"userdel", "-r", "bosh_foobar"}))
		})
	})

	Describe("SetupSsh", func() {
		It("setup ssh", func() {
			fs.HomeDirHomePath = "/some/home/dir"

			platform.SetupSsh("some public key", "vcap")
Esempio n. 2
0
        "provider": "local",
        "options": {
          "blobstore_path": "fake-blobstore-path"
        }
      },
      "vm_provisioner": {
        "agent_provisioner": {
          "infrastructure": null,
          "platform": null,
          "configuration": null,
          "mbus": null
        }
      }
    }`

		err := fs.WriteFileString("/tmp/config", configJSON)
		Expect(err).ToNot(HaveOccurred())

		config, err := NewConfigFromPath("/tmp/config", fs)
		Expect(err).ToNot(HaveOccurred())

		Expect(config.VMProvisioner.AgentProvisioner).To(Equal(
			bpvm.AgentProvisionerConfig{
				Infrastructure: "warden",
				Platform:       "ubuntu",

				Configuration: map[string]interface{}{
					"Platform": map[string]interface{}{
						"Linux": map[string]interface{}{
							"UseDefaultTmpDir":              true,
							"UsePreformattedPersistentDisk": true,
Esempio n. 3
0
func init() {
	const expectedCentosDHCPConfig = `# Generated by bosh-agent

option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;

send host-name "<hostname>";

request subnet-mask, broadcast-address, time-offset, routers,
	domain-name, domain-name-servers, domain-search, host-name,
	netbios-name-servers, netbios-scope, interface-mtu,
	rfc3442-classless-static-routes, ntp-servers;

prepend domain-name-servers zz.zz.zz.zz;
prepend domain-name-servers yy.yy.yy.yy;
prepend domain-name-servers xx.xx.xx.xx;
`

	const expectedCentosIfcfg = `DEVICE=eth0
BOOTPROTO=static
IPADDR=192.168.195.6
NETMASK=255.255.255.0
BROADCAST=192.168.195.255
GATEWAY=192.168.195.1
ONBOOT=yes`

	Describe("centos", func() {
		var (
			collector     *fakestats.FakeStatsCollector
			fs            *fakesys.FakeFileSystem
			cmdRunner     *fakesys.FakeCmdRunner
			diskManager   *fakedisk.FakeDiskManager
			dirProvider   boshdirs.DirectoriesProvider
			platform      Platform
			cdutil        *fakecd.FakeCdUtil
			compressor    boshcmd.Compressor
			copier        boshcmd.Copier
			vitalsService boshvitals.Service
			logger        boshlog.Logger
		)

		BeforeEach(func() {
			collector = &fakestats.FakeStatsCollector{}
			fs = fakesys.NewFakeFileSystem()
			cmdRunner = fakesys.NewFakeCmdRunner()
			diskManager = fakedisk.NewFakeDiskManager()
			dirProvider = boshdirs.NewDirectoriesProvider("/fake-dir")
			cdutil = fakecd.NewFakeCdUtil()
			compressor = boshcmd.NewTarballCompressor(cmdRunner, fs)
			copier = boshcmd.NewCpCopier(cmdRunner, fs)
			vitalsService = boshvitals.NewService(collector, dirProvider)
			logger = boshlog.NewLogger(boshlog.LevelNone)
		})

		JustBeforeEach(func() {
			netManager := boshnet.NewCentosNetManager(fs, cmdRunner, 1*time.Millisecond)

			platform = NewLinuxPlatform(
				fs,
				cmdRunner,
				collector,
				compressor,
				copier,
				dirProvider,
				vitalsService,
				cdutil,
				diskManager,
				netManager,
				1*time.Millisecond,
				logger,
			)
		})

		Describe("SetupDhcp", func() {
			networks := boshsettings.Networks{
				"bosh": boshsettings.Network{
					Default: []string{"dns"},
					DNS:     []string{"xx.xx.xx.xx", "yy.yy.yy.yy", "zz.zz.zz.zz"},
				},
				"vip": boshsettings.Network{
					Default: []string{},
					DNS:     []string{"aa.aa.aa.aa"},
				},
			}

			Context("when dhcp was not previously configured", func() {
				It("writes dhcp configuration", func() {
					err := platform.SetupDhcp(networks)
					Expect(err).ToNot(HaveOccurred())

					dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf")
					Expect(dhcpConfig).ToNot(BeNil())
					Expect(dhcpConfig.StringContents()).To(Equal(expectedCentosDHCPConfig))
				})

				It("restarts network", func() {
					err := platform.SetupDhcp(networks)
					Expect(err).ToNot(HaveOccurred())

					Expect(len(cmdRunner.RunCommands)).To(Equal(1))
					Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network", "restart"}))
				})
			})

			Context("when dhcp was previously configured with different configuration", func() {
				BeforeEach(func() {
					fs.WriteFileString("/etc/dhcp/dhclient.conf", "fake-other-configuration")
				})

				It("updates dhcp configuration", func() {
					err := platform.SetupDhcp(networks)
					Expect(err).ToNot(HaveOccurred())

					dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf")
					Expect(dhcpConfig).ToNot(BeNil())
					Expect(dhcpConfig.StringContents()).To(Equal(expectedCentosDHCPConfig))
				})

				It("restarts network", func() {
					err := platform.SetupDhcp(networks)
					Expect(err).ToNot(HaveOccurred())

					Expect(len(cmdRunner.RunCommands)).To(Equal(1))
					Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network", "restart"}))
				})
			})

			Context("when dhcp was previously configured with same configuration", func() {
				BeforeEach(func() {
					fs.WriteFileString("/etc/dhcp/dhclient.conf", expectedCentosDHCPConfig)
				})

				It("keeps dhcp configuration", func() {
					err := platform.SetupDhcp(networks)
					Expect(err).ToNot(HaveOccurred())

					dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf")
					Expect(dhcpConfig).ToNot(BeNil())
					Expect(dhcpConfig.StringContents()).To(Equal(expectedCentosDHCPConfig))
				})

				It("does not restart network", func() {
					err := platform.SetupDhcp(networks)
					Expect(err).ToNot(HaveOccurred())

					Expect(len(cmdRunner.RunCommands)).To(Equal(0))
				})
			})
		})

		Describe("SetupManualNetworking", func() {
			networks := boshsettings.Networks{
				"bosh": boshsettings.Network{
					Default: []string{"dns", "gateway"},
					IP:      "192.168.195.6",
					Netmask: "255.255.255.0",
					Gateway: "192.168.195.1",
					Mac:     "22:00:0a:1f:ac:2a",
					DNS:     []string{"10.80.130.2", "10.80.130.1"},
				},
			}

			BeforeEach(func() {
				fs.WriteFile("/sys/class/net/eth0", []byte{})
				fs.WriteFileString("/sys/class/net/eth0/address", "22:00:0a:1f:ac:2a\n")
				fs.SetGlob("/sys/class/net/*", []string{"/sys/class/net/eth0"})
			})

			It("sets up centos expected ifconfig", func() {
				err := platform.SetupManualNetworking(networks)
				Expect(err).ToNot(HaveOccurred())

				networkConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-eth0")
				Expect(networkConfig).ToNot(BeNil())
				Expect(networkConfig.StringContents()).To(Equal(expectedCentosIfcfg))
			})

			It("sets up centos /etc/resolv.conf", func() {
				err := platform.SetupManualNetworking(networks)
				Expect(err).ToNot(HaveOccurred())

				resolvConf := fs.GetFileTestStat("/etc/resolv.conf")
				Expect(resolvConf).ToNot(BeNil())
				Expect(resolvConf.StringContents()).To(Equal(expectedCentosResolvConf))
			})

			It("restarts networking", func() {
				err := platform.SetupManualNetworking(networks)
				Expect(err).ToNot(HaveOccurred())

				fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-eth0")
				fs.GetFileTestStat("/etc/resolv.conf")
				time.Sleep(100 * time.Millisecond)

				Expect(len(cmdRunner.RunCommands)).To(Equal(7))
				Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network", "restart"}))
			})

			It("runs arping commands", func() {
				err := platform.SetupManualNetworking(networks)
				Expect(err).ToNot(HaveOccurred())

				fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-eth0")
				fs.GetFileTestStat("/etc/resolv.conf")
				time.Sleep(100 * time.Millisecond)

				Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"}))
				Expect(cmdRunner.RunCommands[6]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"}))
			})
		})
	})
}
Esempio n. 4
0
func init() {
	Describe("concreteV1Service", func() {
		var (
			fs       *fakesys.FakeFileSystem
			platform *fakeplatform.FakePlatform
			specPath = "/spec.json"
			service  V1Service
		)

		BeforeEach(func() {
			fs = fakesys.NewFakeFileSystem()
			platform = fakeplatform.NewFakePlatform()
			service = NewConcreteV1Service(fs, platform, specPath)
		})

		Describe("Get", func() {
			Context("when filesystem has a spec file", func() {
				BeforeEach(func() {
					fs.WriteFileString(specPath, `{"deployment":"fake-deployment-name"}`)
				})

				It("reads spec from filesystem", func() {
					spec, err := service.Get()
					Expect(err).ToNot(HaveOccurred())
					Expect(spec).To(Equal(V1ApplySpec{Deployment: "fake-deployment-name"}))
				})

				It("returns error if reading spec from filesystem errs", func() {
					fs.ReadFileError = errors.New("fake-read-error")

					spec, err := service.Get()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-read-error"))
					Expect(spec).To(Equal(V1ApplySpec{}))
				})
			})

			Context("when filesystem does not have a spec file", func() {
				It("reads spec from filesystem", func() {
					spec, err := service.Get()
					Expect(err).ToNot(HaveOccurred())
					Expect(spec).To(Equal(V1ApplySpec{}))
				})
			})
		})

		Describe("Set", func() {
			newSpec := V1ApplySpec{Deployment: "fake-deployment-name"}

			It("writes spec to filesystem", func() {
				err := service.Set(newSpec)
				Expect(err).ToNot(HaveOccurred())

				specPathStats := fs.GetFileTestStat(specPath)
				Expect(specPathStats).ToNot(BeNil())
				boshassert.MatchesJSONBytes(GinkgoT(), newSpec, specPathStats.Content)
			})

			It("returns error if writing spec to filesystem errs", func() {
				fs.WriteToFileError = errors.New("fake-write-error")

				err := service.Set(newSpec)
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-write-error"))
			})
		})

		Describe("ResolveDynamicNetworks", func() {
			Context("when there is are no dynamic networks", func() {
				unresolvedSpec := V1ApplySpec{
					Deployment: "fake-deployment",
					NetworkSpecs: map[string]NetworkSpec{
						"fake-net": NetworkSpec{
							Fields: map[string]interface{}{"ip": "fake-net-ip"},
						},
					},
				}

				It("returns spec without modifying any networks", func() {
					spec, err := service.ResolveDynamicNetworks(unresolvedSpec)
					Expect(err).ToNot(HaveOccurred())
					Expect(spec).To(Equal(V1ApplySpec{
						Deployment: "fake-deployment",
						NetworkSpecs: map[string]NetworkSpec{
							"fake-net": NetworkSpec{
								Fields: map[string]interface{}{"ip": "fake-net-ip"},
							},
						},
					}))
				})
			})

			Context("when there is one dynamic network", func() {
				unresolvedSpec := V1ApplySpec{
					Deployment: "fake-deployment",
					NetworkSpecs: map[string]NetworkSpec{
						"fake-net1": NetworkSpec{
							Fields: map[string]interface{}{
								"ip":      "fake-net1-ip",
								"netmask": "fake-net1-netmask",
								"gateway": "fake-net1-gateway",
							},
						},
						"fake-net2": NetworkSpec{
							Fields: map[string]interface{}{
								"type":    NetworkSpecTypeDynamic,
								"ip":      "fake-net2-ip",
								"netmask": "fake-net2-netmask",
								"gateway": "fake-net2-gateway",
							},
						},
					},
				}

				Context("when default network can be retrieved", func() {
					BeforeEach(func() {
						platform.GetDefaultNetworkNetwork = boshsettings.Network{
							IP:      "fake-resolved-ip",
							Netmask: "fake-resolved-netmask",
							Gateway: "fake-resolved-gateway",
						}
					})

					It("returns spec with modified dynamic network and keeping everything else the same", func() {
						spec, err := service.ResolveDynamicNetworks(unresolvedSpec)
						Expect(err).ToNot(HaveOccurred())
						Expect(spec).To(Equal(V1ApplySpec{
							Deployment: "fake-deployment",
							NetworkSpecs: map[string]NetworkSpec{
								"fake-net1": NetworkSpec{
									Fields: map[string]interface{}{
										"ip":      "fake-net1-ip",
										"netmask": "fake-net1-netmask",
										"gateway": "fake-net1-gateway",
									},
								},
								"fake-net2": NetworkSpec{
									Fields: map[string]interface{}{
										"type":    NetworkSpecTypeDynamic,
										"ip":      "fake-resolved-ip",
										"netmask": "fake-resolved-netmask",
										"gateway": "fake-resolved-gateway",
									},
								},
							},
						}))
					})
				})

				Context("when default network fails to be retrieved", func() {
					BeforeEach(func() {
						platform.GetDefaultNetworkErr = errors.New("fake-get-default-network-err")
					})

					It("returns error", func() {
						spec, err := service.ResolveDynamicNetworks(unresolvedSpec)
						Expect(err).To(HaveOccurred())
						Expect(err.Error()).To(ContainSubstring("fake-get-default-network-err"))
						Expect(spec).To(Equal(V1ApplySpec{}))
					})
				})
			})

			Context("when there is are multiple dynamic networks", func() {
				unresolvedSpec := V1ApplySpec{
					NetworkSpecs: map[string]NetworkSpec{
						"fake-net1": NetworkSpec{
							Fields: map[string]interface{}{"type": NetworkSpecTypeDynamic},
						},
						"fake-net2": NetworkSpec{
							Fields: map[string]interface{}{"type": NetworkSpecTypeDynamic},
						},
					},
				}

				It("returns error because multiple dynamic networks are not supported", func() {
					spec, err := service.ResolveDynamicNetworks(unresolvedSpec)
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("Multiple dynamic networks are not supported"))
					Expect(spec).To(Equal(V1ApplySpec{}))
				})
			})
		})
	})
}
			failureHandler := func(alert boshalert.MonitAlert) (err error) {
				didHandleAlert = true
				return
			}

			go monit.MonitorJobFailures(failureHandler)

			err := doJobFailureEmail(`fake-other-email`, jobFailuresServerPort)
			Expect(err).ToNot(HaveOccurred())
			Expect(didHandleAlert).To(BeFalse())
		})
	})

	Describe("AddJob", func() {
		BeforeEach(func() {
			fs.WriteFileString("/some/config/path", "fake-config")
		})

		Context("when reading configuration from config path succeeds", func() {
			Context("when writing job configuration succeeds", func() {
				It("returns no error because monit can track added job in jobs directory", func() {
					err := monit.AddJob("router", 0, "/some/config/path")
					Expect(err).ToNot(HaveOccurred())

					writtenConfig, err := fs.ReadFileString(
						dirProvider.MonitJobsDir() + "/0000_router.monitrc")
					Expect(err).ToNot(HaveOccurred())
					Expect(writtenConfig).To(Equal("fake-config"))
				})
			})
Esempio n. 6
0
func init() {
	Describe("concreteCompiler", func() {
		var (
			compiler       Compiler
			compressor     *fakecmd.FakeCompressor
			blobstore      *fakeblobstore.FakeBlobstore
			fs             *fakesys.FakeFileSystem
			runner         *fakesys.FakeCmdRunner
			packageApplier *fakepa.FakePackageApplier
			packagesBc     *fakebc.FakeBundleCollection
		)

		BeforeEach(func() {
			compressor = fakecmd.NewFakeCompressor()
			blobstore = &fakeblobstore.FakeBlobstore{}
			fs = fakesys.NewFakeFileSystem()
			runner = fakesys.NewFakeCmdRunner()
			packageApplier = fakepa.NewFakePackageApplier()
			packagesBc = fakebc.NewFakeBundleCollection()

			compiler = NewConcreteCompiler(
				compressor,
				blobstore,
				fs,
				runner,
				FakeCompileDirProvider{Dir: "/fake-compile-dir"},
				packageApplier,
				packagesBc,
			)
		})

		BeforeEach(func() {
			fs.MkdirAll("/fake-compile-dir", os.ModePerm)
		})

		Describe("Compile", func() {
			var (
				bundle  *fakebc.FakeBundle
				pkg     Package
				pkgDeps []boshmodels.Package
			)

			BeforeEach(func() {
				bundle = packagesBc.FakeGet(boshmodels.Package{
					Name:    "pkg_name",
					Version: "pkg_version",
				})

				bundle.InstallPath = "/fake-dir/data/packages/pkg_name/pkg_version"
				bundle.EnablePath = "/fake-dir/packages/pkg_name"

				compressor.CompressFilesInDirTarballPath = "/tmp/compressed-compiled-package"

				pkg, pkgDeps = getCompileArgs()
			})

			It("returns blob id and sha1 of created compiled package", func() {
				blobstore.CreateBlobID = "fake-blob-id"
				blobstore.CreateFingerprint = "fake-blob-sha1"

				blobID, sha1, err := compiler.Compile(pkg, pkgDeps)
				Expect(err).ToNot(HaveOccurred())

				Expect(blobID).To(Equal("fake-blob-id"))
				Expect(sha1).To(Equal("fake-blob-sha1"))
			})

			It("cleans up all packages before applying dependent packages", func() {
				_, _, err := compiler.Compile(pkg, pkgDeps)
				Expect(err).ToNot(HaveOccurred())
				Expect(packageApplier.ActionsCalled).To(Equal([]string{"KeepOnly", "Apply", "Apply"}))
				Expect(packageApplier.KeptOnlyPackages).To(BeEmpty())
			})

			It("returns an error if cleaning up packages fails", func() {
				packageApplier.KeepOnlyErr = errors.New("fake-keep-only-error")

				_, _, err := compiler.Compile(pkg, pkgDeps)
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-keep-only-error"))
			})

			It("fetches source package from blobstore", func() {
				_, _, err := compiler.Compile(pkg, pkgDeps)
				Expect(err).ToNot(HaveOccurred())

				Expect(blobstore.GetBlobIDs[0]).To(Equal("blobstore_id"))
				Expect(blobstore.GetFingerprints[0]).To(Equal("sha1"))
			})

			It("returns an error if removing compile target directory during uncompression fails", func() {
				fs.RegisterRemoveAllError("/fake-compile-dir/pkg_name", errors.New("fake-remove-error"))

				_, _, err := compiler.Compile(pkg, pkgDeps)
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-remove-error"))
			})

			It("returns an error if creating compile target directory during uncompression fails", func() {
				fs.RegisterMkdirAllError("/fake-compile-dir/pkg_name", errors.New("fake-mkdir-error"))

				_, _, err := compiler.Compile(pkg, pkgDeps)
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-mkdir-error"))
			})

			It("returns an error if removing temporary compile target directory during uncompression fails", func() {
				fs.RegisterRemoveAllError("/fake-compile-dir/pkg_name-bosh-agent-unpack", errors.New("fake-remove-error"))

				_, _, err := compiler.Compile(pkg, pkgDeps)
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-remove-error"))
			})

			It("returns an error if creating temporary compile target directory during uncompression fails", func() {
				fs.RegisterMkdirAllError("/fake-compile-dir/pkg_name-bosh-agent-unpack", errors.New("fake-mkdir-error"))

				_, _, err := compiler.Compile(pkg, pkgDeps)
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-mkdir-error"))
			})

			It("installs dependent packages", func() {
				_, _, err := compiler.Compile(pkg, pkgDeps)
				Expect(err).ToNot(HaveOccurred())
				Expect(packageApplier.AppliedPackages).To(Equal(pkgDeps))
			})

			It("extracts source package to compile dir", func() {
				_, _, err := compiler.Compile(pkg, pkgDeps)
				Expect(err).ToNot(HaveOccurred())

				Expect(fs.FileExists("/fake-compile-dir/pkg_name")).To(BeTrue())
				Expect(compressor.DecompressFileToDirDirs[0]).To(Equal("/fake-compile-dir/pkg_name-bosh-agent-unpack"))
				Expect(compressor.DecompressFileToDirTarballPaths[0]).To(Equal(blobstore.GetFileName))

				Expect(fs.RenameOldPaths[0]).To(Equal("/fake-compile-dir/pkg_name-bosh-agent-unpack"))
				Expect(fs.RenameNewPaths[0]).To(Equal("/fake-compile-dir/pkg_name"))
			})

			It("installs, enables and later cleans up bundle", func() {
				_, _, err := compiler.Compile(pkg, pkgDeps)
				Expect(err).ToNot(HaveOccurred())
				Expect(bundle.ActionsCalled).To(Equal([]string{
					"InstallWithoutContents",
					"Enable",
					"Disable",
					"Uninstall",
				}))
			})

			It("runs packaging script when packaging script exists", func() {
				compressor.DecompressFileToDirCallBack = func() {
					fs.WriteFileString("/fake-compile-dir/pkg_name/packaging", "hi")
				}

				_, _, err := compiler.Compile(pkg, pkgDeps)
				Expect(err).ToNot(HaveOccurred())

				expectedCmd := boshsys.Command{
					Name: "bash",
					Args: []string{"-x", "packaging"},
					Env: map[string]string{
						"BOSH_COMPILE_TARGET":  "/fake-compile-dir/pkg_name",
						"BOSH_INSTALL_TARGET":  "/fake-dir/packages/pkg_name",
						"BOSH_PACKAGE_NAME":    "pkg_name",
						"BOSH_PACKAGE_VERSION": "pkg_version",
					},
					WorkingDir: "/fake-compile-dir/pkg_name",
				}

				Expect(len(runner.RunComplexCommands)).To(Equal(1))
				Expect(runner.RunComplexCommands[0]).To(Equal(expectedCmd))
			})

			It("does not run packaging script when script does not exist", func() {
				_, _, err := compiler.Compile(pkg, pkgDeps)
				Expect(err).ToNot(HaveOccurred())
				Expect(runner.RunCommands).To(BeEmpty())
			})

			It("compresses compiled package", func() {
				_, _, err := compiler.Compile(pkg, pkgDeps)
				Expect(err).ToNot(HaveOccurred())
				Expect(compressor.CompressFilesInDirDir).To(Equal("/fake-dir/data/packages/pkg_name/pkg_version"))
			})

			It("uploads compressed package to blobstore", func() {
				compressor.CompressFilesInDirTarballPath = "/tmp/compressed-compiled-package"

				_, _, err := compiler.Compile(pkg, pkgDeps)
				Expect(err).ToNot(HaveOccurred())
				Expect(blobstore.CreateFileName).To(Equal("/tmp/compressed-compiled-package"))
			})

			It("returs error if uploading compressed package fails", func() {
				blobstore.CreateErr = errors.New("fake-create-err")

				_, _, err := compiler.Compile(pkg, pkgDeps)
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-create-err"))
			})

			It("cleans up compressed package after uploading it to blobstore", func() {
				var beforeCleanUpTarballPath, afterCleanUpTarballPath string

				blobstore.CreateCallBack = func() {
					beforeCleanUpTarballPath = compressor.CleanUpTarballPath
				}

				_, _, err := compiler.Compile(pkg, pkgDeps)
				Expect(err).ToNot(HaveOccurred())

				// Compressed package is not cleaned up before blobstore upload
				Expect(beforeCleanUpTarballPath).To(Equal(""))

				// Deleted after it was uploaded
				afterCleanUpTarballPath = compressor.CleanUpTarballPath
				Expect(afterCleanUpTarballPath).To(Equal("/tmp/compressed-compiled-package"))
			})
		})
	})
}
Esempio n. 7
0
var _ = Describe("LoadConfigFromPath", func() {
	var (
		fs *fakesys.FakeFileSystem
	)

	BeforeEach(func() {
		fs = fakesys.NewFakeFileSystem()
	})

	It("returns populates config", func() {
		fs.WriteFileString("/fake-config.conf", `{
			"Platform": {
				"Linux": {
					"UseDefaultTmpDir": true,
					"UsePreformattedPersistentDisk": true,
					"BindMountPersistentDisk": true
				}
			}
		}`)

		config, err := LoadConfigFromPath(fs, "/fake-config.conf")
		Expect(err).ToNot(HaveOccurred())
		Expect(config).To(Equal(Config{
			Platform: boshplatform.ProviderOptions{
				Linux: boshplatform.LinuxOptions{
					UseDefaultTmpDir:              true,
					UsePreformattedPersistentDisk: true,
					BindMountPersistentDisk:       true,
				},
			},
Esempio n. 8
0
func init() {
	const expectedUbuntuDHCPConfig = `# Generated by bosh-agent

option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;

send host-name "<hostname>";

request subnet-mask, broadcast-address, time-offset, routers,
	domain-name, domain-name-servers, domain-search, host-name,
	netbios-name-servers, netbios-scope, interface-mtu,
	rfc3442-classless-static-routes, ntp-servers;

prepend domain-name-servers zz.zz.zz.zz;
prepend domain-name-servers yy.yy.yy.yy;
prepend domain-name-servers xx.xx.xx.xx;
`

	Describe("ubuntu", func() {
		var (
			collector     *fakestats.FakeStatsCollector
			fs            *fakesys.FakeFileSystem
			cmdRunner     *fakesys.FakeCmdRunner
			diskManager   *fakedisk.FakeDiskManager
			dirProvider   boshdirs.DirectoriesProvider
			platform      Platform
			cdutil        *fakecd.FakeCdUtil
			compressor    boshcmd.Compressor
			copier        boshcmd.Copier
			vitalsService boshvitals.Service
			logger        boshlog.Logger
		)

		BeforeEach(func() {
			collector = &fakestats.FakeStatsCollector{}
			fs = fakesys.NewFakeFileSystem()
			cmdRunner = fakesys.NewFakeCmdRunner()
			diskManager = fakedisk.NewFakeDiskManager()
			dirProvider = boshdirs.NewDirectoriesProvider("/fake-dir")
			cdutil = fakecd.NewFakeCdUtil()
			compressor = boshcmd.NewTarballCompressor(cmdRunner, fs)
			copier = boshcmd.NewCpCopier(cmdRunner, fs)
			vitalsService = boshvitals.NewService(collector, dirProvider)
			logger = boshlog.NewLogger(boshlog.LevelNone)
		})

		JustBeforeEach(func() {
			netManager := boshnet.NewUbuntuNetManager(fs, cmdRunner, 1*time.Millisecond)

			platform = NewLinuxPlatform(
				fs,
				cmdRunner,
				collector,
				compressor,
				copier,
				dirProvider,
				vitalsService,
				cdutil,
				diskManager,
				netManager,
				1*time.Millisecond,
				logger,
			)
		})

		Describe("SetupDhcp", func() {
			networks := boshsettings.Networks{
				"bosh": boshsettings.Network{
					Default: []string{"dns"},
					DNS:     []string{"xx.xx.xx.xx", "yy.yy.yy.yy", "zz.zz.zz.zz"},
				},
				"vip": boshsettings.Network{
					Default: []string{},
					DNS:     []string{"aa.aa.aa.aa"},
				},
			}

			Context("when dhcp was not previously configured", func() {
				It("updates dhclient.conf", func() {
					err := platform.SetupDhcp(networks)
					Expect(err).ToNot(HaveOccurred())

					dhcpConfig := fs.GetFileTestStat("/etc/dhcp3/dhclient.conf")
					Expect(dhcpConfig).ToNot(BeNil())
					Expect(dhcpConfig.StringContents()).To(Equal(expectedUbuntuDHCPConfig))
				})

				It("restarts dhclient", func() {
					err := platform.SetupDhcp(networks)
					Expect(err).ToNot(HaveOccurred())

					Expect(len(cmdRunner.RunCommands)).To(Equal(2))
					Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"pkill", "dhclient3"}))
					Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"/etc/init.d/networking", "restart"}))
				})
			})

			Context("when dhcp was previously configured with different configuration", func() {
				BeforeEach(func() {
					fs.WriteFileString("/etc/dhcp3/dhclient.conf", "fake-other-configuration")
				})

				It("sets up dhcp and restarts dhclient", func() {
					err := platform.SetupDhcp(networks)
					Expect(err).ToNot(HaveOccurred())

					dhcpConfig := fs.GetFileTestStat("/etc/dhcp3/dhclient.conf")
					Expect(dhcpConfig).ToNot(BeNil())
					Expect(dhcpConfig.StringContents()).To(Equal(expectedUbuntuDHCPConfig))
				})

				It("sets up dhcp and restarts dhclient", func() {
					err := platform.SetupDhcp(networks)
					Expect(err).ToNot(HaveOccurred())

					Expect(len(cmdRunner.RunCommands)).To(Equal(2))
					Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"pkill", "dhclient3"}))
					Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"/etc/init.d/networking", "restart"}))
				})
			})

			Context("when dhcp was previously configured with the same configuration", func() {
				BeforeEach(func() {
					fs.WriteFileString("/etc/dhcp3/dhclient.conf", expectedUbuntuDHCPConfig)
				})

				It("does not restart dhclient", func() {
					err := platform.SetupDhcp(networks)
					Expect(err).ToNot(HaveOccurred())

					dhcpConfig := fs.GetFileTestStat("/etc/dhcp3/dhclient.conf")
					Expect(dhcpConfig).ToNot(BeNil())
					Expect(dhcpConfig.StringContents()).To(Equal(expectedUbuntuDHCPConfig))
				})

				It("does not restart dhclient", func() {
					err := platform.SetupDhcp(networks)
					Expect(err).ToNot(HaveOccurred())

					Expect(len(cmdRunner.RunCommands)).To(Equal(0))
				})
			})
		})

		Describe("SetupManualNetworking", func() {
			BeforeEach(func() {
				// For mac addr to interface resolution
				fs.WriteFile("/sys/class/net/eth0", []byte{})
				fs.WriteFileString("/sys/class/net/eth0/address", "22:00:0a:1f:ac:2a\n")
				fs.SetGlob("/sys/class/net/*", []string{"/sys/class/net/eth0"})
			})

			networks := boshsettings.Networks{
				"bosh": boshsettings.Network{
					Default: []string{"dns", "gateway"},
					IP:      "192.168.195.6",
					Netmask: "255.255.255.0",
					Gateway: "192.168.195.1",
					Mac:     "22:00:0a:1f:ac:2a",
					DNS:     []string{"10.80.130.2", "10.80.130.1"},
				},
			}

			Context("when manual networking was not previously configured", func() {
				It("writes /etc/network/interfaces", func() {
					err := platform.SetupManualNetworking(networks)
					Expect(err).ToNot(HaveOccurred())

					networkConfig := fs.GetFileTestStat("/etc/network/interfaces")
					Expect(networkConfig).ToNot(BeNil())
					Expect(networkConfig.StringContents()).To(Equal(expectedUbuntuNetworkInterfaces))
				})

				It("restarts networking", func() {
					err := platform.SetupManualNetworking(networks)
					Expect(err).ToNot(HaveOccurred())

					Expect(len(cmdRunner.RunCommands) >= 2).To(BeTrue())
					Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network-interface", "stop", "INTERFACE=eth0"}))
					Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"service", "network-interface", "start", "INTERFACE=eth0"}))
				})

				It("updates dns", func() {
					err := platform.SetupManualNetworking(networks)
					Expect(err).ToNot(HaveOccurred())

					resolvConf := fs.GetFileTestStat("/etc/resolv.conf")
					Expect(resolvConf).ToNot(BeNil())
					Expect(resolvConf.StringContents()).To(Equal(expectedUbuntuResolvConf))
				})

				It("starts sending arping", func() {
					err := platform.SetupManualNetworking(networks)
					Expect(err).ToNot(HaveOccurred())

					time.Sleep(100 * time.Millisecond)
					Expect(cmdRunner.RunCommands[2]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"}))
					Expect(cmdRunner.RunCommands[7]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"}))
				})
			})

			Context("when manual networking was previously configured with different configuration", func() {
				BeforeEach(func() {
					fs.WriteFileString("/etc/network/interfaces", "fake-manual-config")
				})

				It("updates /etc/network/interfaces", func() {
					err := platform.SetupManualNetworking(networks)
					Expect(err).ToNot(HaveOccurred())

					networkConfig := fs.GetFileTestStat("/etc/network/interfaces")
					Expect(networkConfig).ToNot(BeNil())
					Expect(networkConfig.StringContents()).To(Equal(expectedUbuntuNetworkInterfaces))
				})

				It("restarts networking", func() {
					err := platform.SetupManualNetworking(networks)
					Expect(err).ToNot(HaveOccurred())

					Expect(len(cmdRunner.RunCommands) >= 2).To(BeTrue())
					Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network-interface", "stop", "INTERFACE=eth0"}))
					Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"service", "network-interface", "start", "INTERFACE=eth0"}))
				})

				It("updates dns", func() {
					err := platform.SetupManualNetworking(networks)
					Expect(err).ToNot(HaveOccurred())

					resolvConf := fs.GetFileTestStat("/etc/resolv.conf")
					Expect(resolvConf).ToNot(BeNil())
					Expect(resolvConf.StringContents()).To(Equal(expectedUbuntuResolvConf))
				})

				It("starts sending arping", func() {
					err := platform.SetupManualNetworking(networks)
					Expect(err).ToNot(HaveOccurred())

					time.Sleep(100 * time.Millisecond)
					Expect(cmdRunner.RunCommands[2]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"}))
					Expect(cmdRunner.RunCommands[7]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"}))
				})
			})

			Context("when manual networking was previously configured with same configuration", func() {
				BeforeEach(func() {
					fs.WriteFileString("/etc/network/interfaces", expectedUbuntuNetworkInterfaces)
				})

				It("keeps same /etc/network/interfaces", func() {
					err := platform.SetupManualNetworking(networks)
					Expect(err).ToNot(HaveOccurred())

					networkConfig := fs.GetFileTestStat("/etc/network/interfaces")
					Expect(networkConfig).ToNot(BeNil())
					Expect(networkConfig.StringContents()).To(Equal(expectedUbuntuNetworkInterfaces))
				})

				It("does not restart networking because configuration did not change", func() {
					err := platform.SetupManualNetworking(networks)
					Expect(err).ToNot(HaveOccurred())

					for _, cmd := range cmdRunner.RunCommands {
						Expect(cmd[0]).ToNot(Equal("service"))
					}
				})

				It("updates /etc/resolv.conf for DNS", func() {
					err := platform.SetupManualNetworking(networks)
					Expect(err).ToNot(HaveOccurred())

					resolvConf := fs.GetFileTestStat("/etc/resolv.conf")
					Expect(resolvConf).ToNot(BeNil())
					Expect(resolvConf.StringContents()).To(Equal(expectedUbuntuResolvConf))
				})

				It("starts sending 6 arp ping", func() {
					err := platform.SetupManualNetworking(networks)
					Expect(err).ToNot(HaveOccurred())

					time.Sleep(100 * time.Millisecond)
					Expect(len(cmdRunner.RunCommands)).To(Equal(6))
					Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"}))
					Expect(cmdRunner.RunCommands[5]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"}))
				})
			})
		})
	})
}
func init() {
	Describe("concreteV1Service", func() {
		var (
			fs       *fakesys.FakeFileSystem
			specPath = "/spec.json"
			service  V1Service
		)

		BeforeEach(func() {
			fs = fakesys.NewFakeFileSystem()
			service = NewConcreteV1Service(fs, specPath)
		})

		Describe("Get", func() {
			Context("when filesystem has a spec file", func() {
				BeforeEach(func() {
					fs.WriteFileString(specPath, `{"deployment":"fake-deployment-name"}`)
				})

				It("reads spec from filesystem", func() {
					spec, err := service.Get()
					Expect(err).ToNot(HaveOccurred())
					Expect(spec).To(Equal(V1ApplySpec{Deployment: "fake-deployment-name"}))
				})

				It("returns error if reading spec from filesystem errs", func() {
					fs.ReadFileError = errors.New("fake-read-error")

					spec, err := service.Get()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-read-error"))
					Expect(spec).To(Equal(V1ApplySpec{}))
				})
			})

			Context("when filesystem does not have a spec file", func() {
				It("reads spec from filesystem", func() {
					spec, err := service.Get()
					Expect(err).ToNot(HaveOccurred())
					Expect(spec).To(Equal(V1ApplySpec{}))
				})
			})
		})

		Describe("Set", func() {
			newSpec := V1ApplySpec{Deployment: "fake-deployment-name"}

			It("writes spec to filesystem", func() {
				err := service.Set(newSpec)
				Expect(err).ToNot(HaveOccurred())

				specPathStats := fs.GetFileTestStat(specPath)
				Expect(specPathStats).ToNot(BeNil())
				boshassert.MatchesJSONBytes(GinkgoT(), newSpec, specPathStats.Content)
			})

			It("returns error if writing spec to filesystem errs", func() {
				fs.WriteToFileError = errors.New("fake-write-error")

				err := service.Set(newSpec)
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-write-error"))
			})
		})

		Describe("PopulateDynamicNetworks", func() {
			Context("when there are no dynamic networks", func() {
				unresolvedSpec := V1ApplySpec{
					Deployment: "fake-deployment",
					NetworkSpecs: map[string]NetworkSpec{
						"fake-net": NetworkSpec{
							Fields: map[string]interface{}{"ip": "fake-net-ip"},
						},
					},
				}

				It("returns spec without modifying any networks", func() {
					spec, err := service.PopulateDynamicNetworks(unresolvedSpec, boshsettings.Settings{})
					Expect(err).ToNot(HaveOccurred())
					Expect(spec).To(Equal(V1ApplySpec{
						Deployment: "fake-deployment",
						NetworkSpecs: map[string]NetworkSpec{
							"fake-net": NetworkSpec{
								Fields: map[string]interface{}{"ip": "fake-net-ip"},
							},
						},
					}))
				})
			})

			Context("when there are dynamic networks", func() {
				unresolvedSpec := V1ApplySpec{
					Deployment: "fake-deployment",
					NetworkSpecs: map[string]NetworkSpec{
						"fake-net1": NetworkSpec{
							Fields: map[string]interface{}{
								"ip":      "fake-net1-ip",
								"netmask": "fake-net1-netmask",
								"gateway": "fake-net1-gateway",
							},
						},
						"fake-net2": NetworkSpec{
							Fields: map[string]interface{}{
								"type":    NetworkSpecTypeDynamic,
								"ip":      "fake-net2-ip",
								"netmask": "fake-net2-netmask",
								"gateway": "fake-net2-gateway",
							},
						},
						"fake-net3": NetworkSpec{
							Fields: map[string]interface{}{
								"type":    NetworkSpecTypeDynamic,
								"ip":      "fake-net3-ip",
								"netmask": "fake-net3-netmask",
								"gateway": "fake-net3-gateway",
							},
						},
					},
				}

				Context("when associated network is in settings", func() {
					settings := boshsettings.Settings{
						Networks: boshsettings.Networks{
							"fake-net1": boshsettings.Network{
								IP:      "fake-resolved1-ip",
								Netmask: "fake-resolved1-netmask",
								Gateway: "fake-resolved1-gateway",
							},
							"fake-net2": boshsettings.Network{
								IP:      "fake-resolved2-ip",
								Netmask: "fake-resolved2-netmask",
								Gateway: "fake-resolved2-gateway",
							},
							"fake-net3": boshsettings.Network{
								IP:      "fake-resolved3-ip",
								Netmask: "fake-resolved3-netmask",
								Gateway: "fake-resolved3-gateway",
							},
						},
					}

					It("returns spec with modified dynamic networks and keeping everything else the same", func() {
						spec, err := service.PopulateDynamicNetworks(unresolvedSpec, settings)
						Expect(err).ToNot(HaveOccurred())
						Expect(spec).To(Equal(V1ApplySpec{
							Deployment: "fake-deployment",
							NetworkSpecs: map[string]NetworkSpec{
								"fake-net1": NetworkSpec{
									Fields: map[string]interface{}{ // ip info not replaced
										"ip":      "fake-net1-ip",
										"netmask": "fake-net1-netmask",
										"gateway": "fake-net1-gateway",
									},
								},
								"fake-net2": NetworkSpec{
									Fields: map[string]interface{}{
										"type":    NetworkSpecTypeDynamic,
										"ip":      "fake-resolved2-ip",
										"netmask": "fake-resolved2-netmask",
										"gateway": "fake-resolved2-gateway",
									},
								},
								"fake-net3": NetworkSpec{
									Fields: map[string]interface{}{
										"type":    NetworkSpecTypeDynamic,
										"ip":      "fake-resolved3-ip",
										"netmask": "fake-resolved3-netmask",
										"gateway": "fake-resolved3-gateway",
									},
								},
							},
						}))
					})
				})

				Context("when associated network cannot be found in settings", func() {
					It("returns error", func() {
						spec, err := service.PopulateDynamicNetworks(unresolvedSpec, boshsettings.Settings{})
						Expect(err).To(Equal(errors.New("Network fake-net2 is not found in settings")))
						Expect(spec).To(Equal(V1ApplySpec{}))
					})
				})
			})
		})
	})
}
			Expect(err.Error()).To(ContainSubstring("missing blobstore_path"))
		})

		It("returns error when blobstore path is not a string", func() {
			options := map[string]interface{}{"blobstore_path": 443}
			blobstore = NewLocalBlobstore(fs, uuidGen, options)

			err := blobstore.Validate()
			Expect(err).To(HaveOccurred())
			Expect(err.Error()).To(ContainSubstring("blobstore_path must be a string"))
		})
	})

	Describe("Get", func() {
		It("local get", func() {
			fs.WriteFileString(fakeBlobstorePath+"/fake-blob-id", "fake contents")

			tempFile, err := fs.TempFile("bosh-blobstore-local-TestLocalGet")
			Expect(err).ToNot(HaveOccurred())

			fs.ReturnTempFile = tempFile
			defer fs.RemoveAll(tempFile.Name())

			_, err = blobstore.Get("fake-blob-id", "")
			Expect(err).ToNot(HaveOccurred())

			fileStats := fs.GetFileTestStat(tempFile.Name())
			Expect(fileStats).ToNot(BeNil())
			Expect("fake contents").To(Equal(fileStats.StringContents()))
		})
Esempio n. 11
0
func init() {
	Describe("concreteV1Service", func() {
		var (
			fs       *fakesys.FakeFileSystem
			specPath string
			service  V1Service
		)

		BeforeEach(func() {
			fs = fakesys.NewFakeFileSystem()
			specPath = "/spec.json"
			service = NewConcreteV1Service(fs, specPath)
		})

		Describe("Get", func() {
			Context("when filesystem has a spec file", func() {
				BeforeEach(func() {
					fs.WriteFileString(specPath, `{"deployment":"fake-deployment-name"}`)
				})

				It("reads spec from filesystem", func() {
					spec, err := service.Get()
					Expect(err).ToNot(HaveOccurred())
					Expect(spec).To(Equal(V1ApplySpec{Deployment: "fake-deployment-name"}))
				})

				It("returns error if reading spec from filesystem errs", func() {
					fs.ReadFileError = errors.New("fake-read-error")

					spec, err := service.Get()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-read-error"))
					Expect(spec).To(Equal(V1ApplySpec{}))
				})
			})

			Context("when filesystem does not have a spec file", func() {
				It("reads spec from filesystem", func() {
					spec, err := service.Get()
					Expect(err).ToNot(HaveOccurred())
					Expect(spec).To(Equal(V1ApplySpec{}))
				})
			})
		})

		Describe("Set", func() {
			newSpec := V1ApplySpec{Deployment: "fake-deployment-name"}

			It("writes spec to filesystem", func() {
				err := service.Set(newSpec)
				Expect(err).ToNot(HaveOccurred())

				specPathStats := fs.GetFileTestStat(specPath)
				Expect(specPathStats).ToNot(BeNil())
				boshassert.MatchesJSONBytes(GinkgoT(), newSpec, specPathStats.Content)
			})

			It("returns error if writing spec to filesystem errs", func() {
				fs.WriteToFileError = errors.New("fake-write-error")

				err := service.Set(newSpec)
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-write-error"))
			})
		})

	})
}
Esempio n. 12
0
				Expect(err).ToNot(HaveOccurred())

				Expect(len(cmdRunner.RunCommands)).To(Equal(1))
				Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network", "restart"}))
			})
		}

		Context("when dhcp was not previously configured", func() {
			ItUpdatesDhcpConfig()
			ItRestartsDhcp()
			ItBroadcastsMACAddresses()
		})

		Context("when dhcp was previously configured with different configuration", func() {
			BeforeEach(func() {
				fs.WriteFileString(dhcpConfPath, "fake-other-configuration")
			})

			ItUpdatesDhcpConfig()
			ItRestartsDhcp()
			ItBroadcastsMACAddresses()
		})

		Context("when dhcp was previously configured with same configuration", func() {
			BeforeEach(func() {
				fs.WriteFileString(dhcpConfPath, expectedDHCPConfig)
			})

			It("keeps dhcp configuration", func() {
				err := netManager.SetupDhcp(networks, nil)
				Expect(err).ToNot(HaveOccurred())
Esempio n. 13
0
				}))
			})
		}

		Context("when dhclient3 is installed on the system", func() {
			BeforeEach(func() { cmdRunner.CommandExistsValue = true })

			Context("when dhcp was not previously configured", func() {
				ItUpdatesDhcpConfig(dhcp3ConfPath)
				ItRestartsDhcp()
				ItBroadcastsMACAddresses()
			})

			Context("when dhcp was previously configured with different configuration", func() {
				BeforeEach(func() {
					fs.WriteFileString(dhcp3ConfPath, "fake-other-configuration")
				})

				ItUpdatesDhcpConfig(dhcp3ConfPath)
				ItRestartsDhcp()
				ItBroadcastsMACAddresses()
			})

			Context("when dhcp was previously configured with the same configuration", func() {
				BeforeEach(func() {
					fs.WriteFileString(dhcp3ConfPath, expectedDHCPConfig)
				})

				ItUpdatesDhcpConfig(dhcp3ConfPath)
				ItDoesNotRestartDhcp()
				ItBroadcastsMACAddresses()
		Context("when incorrect http method is used", func() {
			It("returns a 404", func() {
				waitForServerToStart(serverURL, "agent", httpClient)

				httpResponse, err := httpClient.Get(serverURL + "/agent")

				Expect(err).ToNot(HaveOccurred())
				Expect(httpResponse.StatusCode).To(Equal(404))
			})
		})
	})

	Describe("GET /blobs", func() {
		It("returns data from file system", func() {
			fs.WriteFileString("/var/vcap/micro_bosh/data/cache/123-456-789", "Some data")

			httpResponse, err := httpClient.Get(serverURL + "/blobs/a5/123-456-789")
			for err != nil {
				httpResponse, err = httpClient.Get(serverURL + "/blobs/a5/123-456-789")
			}
			defer httpResponse.Body.Close()

			httpBody, readErr := ioutil.ReadAll(httpResponse.Body)
			Expect(readErr).ToNot(HaveOccurred())
			Expect(httpResponse.StatusCode).To(Equal(200))
			Expect(httpBody).To(Equal([]byte("Some data")))
		})

		Context("when incorrect http method is used", func() {
			It("returns a 404", func() {
Esempio n. 15
0
func init() {
	Describe("monitJobSupervisor", func() {
		var (
			fs                    *fakesys.FakeFileSystem
			runner                *fakesys.FakeCmdRunner
			client                *fakemonit.FakeMonitClient
			logger                boshlog.Logger
			dirProvider           boshdir.DirectoriesProvider
			jobFailuresServerPort int
			monit                 JobSupervisor
		)

		BeforeEach(func() {
			fs = &fakesys.FakeFileSystem{}
			runner = &fakesys.FakeCmdRunner{}
			client = fakemonit.NewFakeMonitClient()
			logger = boshlog.NewLogger(boshlog.LevelNone)
			dirProvider = boshdir.NewDirectoriesProvider("/var/vcap")
			jobFailuresServerPort = getJobFailureServerPort()

			monit = NewMonitJobSupervisor(
				fs,
				runner,
				client,
				logger,
				dirProvider,
				jobFailuresServerPort,
				0*time.Millisecond,
			)
		})

		It("waits until the job is reloaded", func() {
			client.Incarnations = []int{1, 1, 1, 2, 3}
			client.StatusStatus = fakemonit.FakeMonitStatus{
				Services: []boshmonit.Service{
					boshmonit.Service{Monitored: true, Status: "failing"},
					boshmonit.Service{Monitored: true, Status: "running"},
				},
				Incarnation: 1,
			}

			err := monit.Reload()

			Expect(err).ToNot(HaveOccurred())
			Expect(1).To(Equal(len(runner.RunCommands)))
			Expect(runner.RunCommands[0]).To(Equal([]string{"monit", "reload"}))
			Expect(client.StatusCalledTimes).To(Equal(4))
		})

		It("stops trying to reload after 60 attempts", func() {
			for i := 0; i < 61; i++ {
				client.Incarnations = append(client.Incarnations, 1)
			}

			client.StatusStatus = fakemonit.FakeMonitStatus{
				Services: []boshmonit.Service{
					boshmonit.Service{Monitored: true, Status: "failing"},
					boshmonit.Service{Monitored: true, Status: "running"},
				},
				Incarnation: 1,
			}

			err := monit.Reload()

			Expect(err).To(HaveOccurred())
			Expect(1).To(Equal(len(runner.RunCommands)))
			Expect(runner.RunCommands[0]).To(Equal([]string{"monit", "reload"}))
			Expect(client.StatusCalledTimes).To(Equal(60))
		})

		It("start starts each monit service in group vcap", func() {
			client.ServicesInGroupServices = []string{"fake-service"}

			err := monit.Start()
			Expect(err).ToNot(HaveOccurred())

			Expect("vcap").To(Equal(client.ServicesInGroupName))
			Expect(1).To(Equal(len(client.StartServiceNames)))
			Expect("fake-service").To(Equal(client.StartServiceNames[0]))
		})

		It("stop stops each monit service in group vcap", func() {
			client.ServicesInGroupServices = []string{"fake-service"}

			err := monit.Stop()
			Expect(err).ToNot(HaveOccurred())

			Expect("vcap").To(Equal(client.ServicesInGroupName))
			Expect(1).To(Equal(len(client.StopServiceNames)))
			Expect("fake-service").To(Equal(client.StopServiceNames[0]))
		})

		It("status returns running when all services are monitored and running", func() {
			client.StatusStatus = fakemonit.FakeMonitStatus{
				Services: []boshmonit.Service{
					boshmonit.Service{Monitored: true, Status: "running"},
					boshmonit.Service{Monitored: true, Status: "running"},
				},
			}

			status := monit.Status()
			Expect("running").To(Equal(status))
		})

		It("status returns failing when all services are monitored and at least one service is failing", func() {
			client.StatusStatus = fakemonit.FakeMonitStatus{
				Services: []boshmonit.Service{
					boshmonit.Service{Monitored: true, Status: "failing"},
					boshmonit.Service{Monitored: true, Status: "running"},
				},
			}

			status := monit.Status()
			Expect("failing").To(Equal(status))
		})

		It("status returns failing when at least one service is not monitored", func() {
			client.StatusStatus = fakemonit.FakeMonitStatus{
				Services: []boshmonit.Service{
					boshmonit.Service{Monitored: false, Status: "running"},
					boshmonit.Service{Monitored: true, Status: "running"},
				},
			}

			status := monit.Status()
			Expect("failing").To(Equal(status))
		})

		It("status returns start when at least one service is starting", func() {
			client.StatusStatus = fakemonit.FakeMonitStatus{
				Services: []boshmonit.Service{
					boshmonit.Service{Monitored: true, Status: "failing"},
					boshmonit.Service{Monitored: true, Status: "starting"},
					boshmonit.Service{Monitored: true, Status: "running"},
				},
			}

			status := monit.Status()
			Expect("starting").To(Equal(status))
		})

		It("status returns unknown when error", func() {
			client.StatusErr = errors.New("fake-monit-client-error")

			status := monit.Status()
			Expect("unknown").To(Equal(status))
		})

		It("monitor job failures", func() {
			var handledAlert boshalert.MonitAlert

			failureHandler := func(alert boshalert.MonitAlert) (err error) {
				handledAlert = alert
				return
			}

			go monit.MonitorJobFailures(failureHandler)

			msg := `Message-id: <1304319946.0@localhost>
    Service: nats
    Event: does not exist
    Action: restart
    Date: Sun, 22 May 2011 20:07:41 +0500
    Description: process is not running`

			err := doJobFailureEmail(msg, jobFailuresServerPort)
			Expect(err).ToNot(HaveOccurred())

			assert.Equal(GinkgoT(), handledAlert, boshalert.MonitAlert{
				ID:          "1304319946.0@localhost",
				Service:     "nats",
				Event:       "does not exist",
				Action:      "restart",
				Date:        "Sun, 22 May 2011 20:07:41 +0500",
				Description: "process is not running",
			})
		})

		It("monitor job failures ignores other emails", func() {
			var didHandleAlert bool

			failureHandler := func(alert boshalert.MonitAlert) (err error) {
				didHandleAlert = true
				return
			}

			go monit.MonitorJobFailures(failureHandler)

			msg := `Hi! How'sit goin`

			err := doJobFailureEmail(msg, jobFailuresServerPort)
			Expect(err).ToNot(HaveOccurred())
			Expect(didHandleAlert).To(BeFalse())
		})

		Describe("AddJob", func() {
			BeforeEach(func() {
				fs.WriteFileString("/some/config/path", "fake-config")
			})

			Context("when reading configuration from config path succeeds", func() {
				Context("when writing job configuration succeeds", func() {
					It("returns no error because monit can track added job in jobs directory", func() {
						err := monit.AddJob("router", 0, "/some/config/path")
						Expect(err).ToNot(HaveOccurred())

						writtenConfig, err := fs.ReadFileString(
							dirProvider.MonitJobsDir() + "/0000_router.monitrc")
						Expect(err).ToNot(HaveOccurred())
						Expect(writtenConfig).To(Equal("fake-config"))
					})
				})

				Context("when writing job configuration fails", func() {
					It("returns error", func() {
						fs.WriteToFileError = errors.New("fake-write-error")

						err := monit.AddJob("router", 0, "/some/config/path")
						Expect(err).To(HaveOccurred())
						Expect(err.Error()).To(ContainSubstring("fake-write-error"))
					})
				})
			})

			Context("when reading configuration from config path fails", func() {
				It("returns error", func() {
					fs.ReadFileError = errors.New("fake-read-error")

					err := monit.AddJob("router", 0, "/some/config/path")
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-read-error"))
				})
			})
		})

		Describe("RemoveAllJobs", func() {
			Context("when jobs directory removal succeeds", func() {
				It("does not return error because all jobs are removed from monit", func() {
					jobsDir := dirProvider.MonitJobsDir()
					jobBasename := "/0000_router.monitrc"
					fs.WriteFileString(jobsDir+jobBasename, "fake-added-job")

					err := monit.RemoveAllJobs()
					Expect(err).ToNot(HaveOccurred())

					Expect(fs.FileExists(jobsDir)).To(BeFalse())
					Expect(fs.FileExists(jobsDir + jobBasename)).To(BeFalse())
				})
			})

			Context("when jobs directory removal fails", func() {
				It("returns error if removing jobs directory fails", func() {
					fs.RemoveAllError = errors.New("fake-remove-all-error")

					err := monit.RemoveAllJobs()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-remove-all-error"))
				})
			})
		})

		Describe("Unmonitor", func() {
			BeforeEach(func() {
				client.ServicesInGroupServices = []string{"fake-srv-1", "fake-srv-2", "fake-srv-3"}
				client.UnmonitorServiceErrs = []error{nil, nil, nil}
			})

			Context("when all services succeed to be unmonitored", func() {
				It("returns no error because all services got unmonitored", func() {
					err := monit.Unmonitor()
					Expect(err).ToNot(HaveOccurred())

					Expect(client.ServicesInGroupName).To(Equal("vcap"))
					Expect(client.UnmonitorServiceNames).To(Equal(
						[]string{"fake-srv-1", "fake-srv-2", "fake-srv-3"}))
				})
			})

			Context("when at least one service fails to be unmonitored", func() {
				BeforeEach(func() {
					client.UnmonitorServiceErrs = []error{
						nil, errors.New("fake-unmonitor-error"), nil,
					}
				})

				It("returns first unmonitor error", func() {
					err := monit.Unmonitor()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-unmonitor-error"))
				})

				It("only tries to unmonitor services before the first unmonitor error", func() {
					err := monit.Unmonitor()
					Expect(err).To(HaveOccurred())
					Expect(client.ServicesInGroupName).To(Equal("vcap"))
					Expect(client.UnmonitorServiceNames).To(Equal([]string{"fake-srv-1", "fake-srv-2"}))
				})
			})

			Context("when failed retrieving list of services", func() {
				It("returns error", func() {
					client.ServicesInGroupErr = errors.New("fake-services-error")

					err := monit.Unmonitor()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-services-error"))
				})
			})
		})
	})
}
Esempio n. 16
0
func init() {
	const expectedUbuntuDHCPConfig = `# Generated by bosh-agent

option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;

send host-name "<hostname>";

request subnet-mask, broadcast-address, time-offset, routers,
	domain-name, domain-name-servers, domain-search, host-name,
	netbios-name-servers, netbios-scope, interface-mtu,
	rfc3442-classless-static-routes, ntp-servers;

prepend domain-name-servers zz.zz.zz.zz, yy.yy.yy.yy, xx.xx.xx.xx;
`

	Describe("ubuntuNetManager", func() {
		var (
			fs                     *fakesys.FakeFileSystem
			cmdRunner              *fakesys.FakeCmdRunner
			defaultNetworkResolver *fakenet.FakeDefaultNetworkResolver
			netManager             NetManager
		)

		BeforeEach(func() {
			fs = fakesys.NewFakeFileSystem()
			cmdRunner = fakesys.NewFakeCmdRunner()
			defaultNetworkResolver = &fakenet.FakeDefaultNetworkResolver{}
			logger := boshlog.NewLogger(boshlog.LevelNone)
			netManager = NewUbuntuNetManager(fs, cmdRunner, defaultNetworkResolver, 1*time.Millisecond, logger)
		})

		Describe("SetupDhcp", func() {
			networks := boshsettings.Networks{
				"bosh": boshsettings.Network{
					Default: []string{"dns"},
					DNS:     []string{"xx.xx.xx.xx", "yy.yy.yy.yy", "zz.zz.zz.zz"},
				},
				"vip": boshsettings.Network{
					Default: []string{},
					DNS:     []string{"aa.aa.aa.aa"},
				},
			}

			ItRestartsDhcp := func() {
				Context("when ifconfig version is 0.7", func() {
					BeforeEach(func() {
						cmdRunner.AddCmdResult("ifup --version", fakesys.FakeCmdResult{
							Stdout: "ifup version 0.7.47",
						})
					})

					It("restarts dhclient", func() {
						err := netManager.SetupDhcp(networks)
						Expect(err).ToNot(HaveOccurred())

						Expect(len(cmdRunner.RunCommands)).To(Equal(3))
						Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"ifdown", "-a", "--no-loopback"}))
						Expect(cmdRunner.RunCommands[2]).To(Equal([]string{"ifup", "-a", "--no-loopback"}))
					})
				})

				Context("when ifconfig version is 0.6", func() {
					BeforeEach(func() {
						cmdRunner.AddCmdResult("ifup --version", fakesys.FakeCmdResult{
							Stdout: "ifup version 0.6.0",
						})
					})

					It("restarts dhclient", func() {
						err := netManager.SetupDhcp(networks)
						Expect(err).ToNot(HaveOccurred())

						Expect(len(cmdRunner.RunCommands)).To(Equal(3))
						Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"ifdown", "-a", "--exclude=lo"}))
						Expect(cmdRunner.RunCommands[2]).To(Equal([]string{"ifup", "-a", "--exclude=lo"}))
					})
				})
			}

			ItUpdatesDhcp3Config := func() {
				It("updates /etc/dhcp3/dhclient.conf", func() {
					err := netManager.SetupDhcp(networks)
					Expect(err).ToNot(HaveOccurred())

					dhcpConfig := fs.GetFileTestStat("/etc/dhcp3/dhclient.conf")
					Expect(dhcpConfig).ToNot(BeNil())
					Expect(dhcpConfig.StringContents()).To(Equal(expectedUbuntuDHCPConfig))
				})
			}

			ItUpdatesDhcpConfig := func() {
				It("updates /etc/dhcp/dhclient.conf", func() {
					err := netManager.SetupDhcp(networks)
					Expect(err).ToNot(HaveOccurred())

					dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf")
					Expect(dhcpConfig).ToNot(BeNil())
					Expect(dhcpConfig.StringContents()).To(Equal(expectedUbuntuDHCPConfig))
				})
			}

			ItDoesNotRestartDhcp := func() {
				It("does not restart dhclient", func() {
					err := netManager.SetupDhcp(networks)
					Expect(err).ToNot(HaveOccurred())

					Expect(len(cmdRunner.RunCommands)).To(Equal(0))
				})
			}

			Context("when dhclient3 is installed on the system", func() {
				BeforeEach(func() { cmdRunner.CommandExistsValue = true })

				Context("when dhcp was not previously configured", func() {
					ItUpdatesDhcp3Config()
					ItRestartsDhcp()
				})

				Context("when dhcp was previously configured with different configuration", func() {
					BeforeEach(func() {
						fs.WriteFileString("/etc/dhcp3/dhclient.conf", "fake-other-configuration")
					})

					ItUpdatesDhcp3Config()
					ItRestartsDhcp()
				})

				Context("when dhcp was previously configured with the same configuration", func() {
					BeforeEach(func() {
						fs.WriteFileString("/etc/dhcp3/dhclient.conf", expectedUbuntuDHCPConfig)
					})

					ItUpdatesDhcp3Config()
					ItDoesNotRestartDhcp()
				})
			})

			Context("when dhclient3 is not installed on the system", func() {
				BeforeEach(func() { cmdRunner.CommandExistsValue = false })

				Context("when dhcp was not previously configured", func() {
					ItUpdatesDhcpConfig()
					ItRestartsDhcp()
				})

				Context("when dhcp was previously configured with different configuration", func() {
					BeforeEach(func() {
						fs.WriteFileString("/etc/dhcp/dhclient.conf", "fake-other-configuration")
					})

					ItUpdatesDhcpConfig()
					ItRestartsDhcp()
				})

				Context("when dhcp was previously configured with the same configuration", func() {
					BeforeEach(func() {
						fs.WriteFileString("/etc/dhcp/dhclient.conf", expectedUbuntuDHCPConfig)
					})

					ItUpdatesDhcpConfig()
					ItDoesNotRestartDhcp()
				})
			})
		})

		Describe("SetupManualNetworking", func() {
			var errCh chan error

			BeforeEach(func() {
				errCh = make(chan error)
			})

			BeforeEach(func() {
				// For mac addr to interface resolution
				fs.WriteFile("/sys/class/net/eth0", []byte{})
				fs.WriteFileString("/sys/class/net/eth0/address", "22:00:0a:1f:ac:2a\n")
				fs.SetGlob("/sys/class/net/*", []string{"/sys/class/net/eth0"})
			})

			networks := boshsettings.Networks{
				"bosh": boshsettings.Network{
					Default: []string{"dns", "gateway"},
					IP:      "192.168.195.6",
					Netmask: "255.255.255.0",
					Gateway: "192.168.195.1",
					Mac:     "22:00:0a:1f:ac:2a",
					DNS:     []string{"10.80.130.2", "10.80.130.1"},
				},
			}

			Context("when manual networking was not previously configured", func() {
				It("writes /etc/network/interfaces", func() {
					err := netManager.SetupManualNetworking(networks, nil)
					Expect(err).ToNot(HaveOccurred())

					networkConfig := fs.GetFileTestStat("/etc/network/interfaces")
					Expect(networkConfig).ToNot(BeNil())
					Expect(networkConfig.StringContents()).To(Equal(expectedUbuntuNetworkInterfaces))
				})

				It("restarts networking", func() {
					err := netManager.SetupManualNetworking(networks, errCh)
					Expect(err).ToNot(HaveOccurred())

					<-errCh // wait for all arpings

					Expect(len(cmdRunner.RunCommands) >= 2).To(BeTrue())
					Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network-interface", "stop", "INTERFACE=eth0"}))
					Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"service", "network-interface", "start", "INTERFACE=eth0"}))
				})

				It("updates dns", func() {
					err := netManager.SetupManualNetworking(networks, nil)
					Expect(err).ToNot(HaveOccurred())

					resolvConf := fs.GetFileTestStat("/etc/resolv.conf")
					Expect(resolvConf).ToNot(BeNil())
					Expect(resolvConf.StringContents()).To(Equal(expectedUbuntuResolvConf))
				})

				It("starts sending arping", func() {
					err := netManager.SetupManualNetworking(networks, errCh)
					Expect(err).ToNot(HaveOccurred())

					<-errCh // wait for all arpings

					Expect(cmdRunner.RunCommands[2]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"}))
					Expect(cmdRunner.RunCommands[7]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"}))
				})
			})

			Context("when manual networking was previously configured with different configuration", func() {
				BeforeEach(func() {
					fs.WriteFileString("/etc/network/interfaces", "fake-manual-config")
				})

				It("updates /etc/network/interfaces", func() {
					err := netManager.SetupManualNetworking(networks, nil)
					Expect(err).ToNot(HaveOccurred())

					networkConfig := fs.GetFileTestStat("/etc/network/interfaces")
					Expect(networkConfig).ToNot(BeNil())
					Expect(networkConfig.StringContents()).To(Equal(expectedUbuntuNetworkInterfaces))
				})

				It("restarts networking", func() {
					err := netManager.SetupManualNetworking(networks, errCh)
					Expect(err).ToNot(HaveOccurred())

					<-errCh // wait for all arpings

					Expect(len(cmdRunner.RunCommands) >= 2).To(BeTrue())
					Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network-interface", "stop", "INTERFACE=eth0"}))
					Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"service", "network-interface", "start", "INTERFACE=eth0"}))
				})

				It("updates dns", func() {
					err := netManager.SetupManualNetworking(networks, nil)
					Expect(err).ToNot(HaveOccurred())

					resolvConf := fs.GetFileTestStat("/etc/resolv.conf")
					Expect(resolvConf).ToNot(BeNil())
					Expect(resolvConf.StringContents()).To(Equal(expectedUbuntuResolvConf))
				})

				It("starts sending 6 arp pings", func() {
					err := netManager.SetupManualNetworking(networks, errCh)
					Expect(err).ToNot(HaveOccurred())

					<-errCh // wait for all arpings

					Expect(cmdRunner.RunCommands[2]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"}))
					Expect(cmdRunner.RunCommands[7]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"}))
				})
			})

			Context("when manual networking was previously configured with same configuration", func() {
				BeforeEach(func() {
					fs.WriteFileString("/etc/network/interfaces", expectedUbuntuNetworkInterfaces)
				})

				It("keeps same /etc/network/interfaces", func() {
					err := netManager.SetupManualNetworking(networks, nil)
					Expect(err).ToNot(HaveOccurred())

					networkConfig := fs.GetFileTestStat("/etc/network/interfaces")
					Expect(networkConfig).ToNot(BeNil())
					Expect(networkConfig.StringContents()).To(Equal(expectedUbuntuNetworkInterfaces))
				})

				It("does not restart networking because configuration did not change", func() {
					err := netManager.SetupManualNetworking(networks, errCh)
					Expect(err).ToNot(HaveOccurred())

					<-errCh // wait for all arpings

					for _, cmd := range cmdRunner.RunCommands {
						Expect(cmd[0]).ToNot(Equal("service"))
					}
				})

				It("updates /etc/resolv.conf for DNS", func() {
					err := netManager.SetupManualNetworking(networks, nil)
					Expect(err).ToNot(HaveOccurred())

					resolvConf := fs.GetFileTestStat("/etc/resolv.conf")
					Expect(resolvConf).ToNot(BeNil())
					Expect(resolvConf.StringContents()).To(Equal(expectedUbuntuResolvConf))
				})

				It("starts sending 6 arp ping", func() {
					err := netManager.SetupManualNetworking(networks, errCh)
					Expect(err).ToNot(HaveOccurred())

					<-errCh // wait for all arpings

					Expect(len(cmdRunner.RunCommands)).To(Equal(6))
					Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"}))
					Expect(cmdRunner.RunCommands[5]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"}))
				})
			})
		})
	})
}
		fs       *fakesys.FakeFileSystem
		searcher MountsSearcher
	)

	BeforeEach(func() {
		fs = fakesys.NewFakeFileSystem()
		searcher = NewProcMountsSearcher(fs)
	})

	Describe("SearchMounts", func() {
		Context("when reading /proc/mounts succeeds", func() {
			It("returns parsed mount information", func() {
				fs.WriteFileString(
					"/proc/mounts",
					`none /run/lock tmpfs rw,nosuid,nodev,noexec,relatime,size=5120k 0 0
none /run/shm tmpfs rw,nosuid,nodev,relatime 0 0
/dev/sda1 /boot ext2 rw,relatime,errors=continue 0 0
none /tmp/warden/cgroup tmpfs rw,relatime 0 0`,
				)

				mounts, err := searcher.SearchMounts()
				Expect(err).ToNot(HaveOccurred())
				Expect(mounts).To(Equal([]Mount{
					Mount{PartitionPath: "none", MountPoint: "/run/lock"},
					Mount{PartitionPath: "none", MountPoint: "/run/shm"},
					Mount{PartitionPath: "/dev/sda1", MountPoint: "/boot"},
					Mount{PartitionPath: "none", MountPoint: "/tmp/warden/cgroup"},
				}))
			})

			It("ignores empty lines", func() {
Esempio n. 18
0
func init() {
	Describe("renderedJobApplier", func() {
		var (
			jobsBc                 *fakebc.FakeBundleCollection
			jobSupervisor          *fakejobsuper.FakeJobSupervisor
			packageApplierProvider *fakepa.FakePackageApplierProvider
			blobstore              *fakeblob.FakeBlobstore
			compressor             *fakecmd.FakeCompressor
			fs                     *fakesys.FakeFileSystem
			applier                JobApplier
		)

		BeforeEach(func() {
			jobsBc = fakebc.NewFakeBundleCollection()
			jobSupervisor = fakejobsuper.NewFakeJobSupervisor()
			packageApplierProvider = fakepa.NewFakePackageApplierProvider()
			blobstore = fakeblob.NewFakeBlobstore()
			fs = fakesys.NewFakeFileSystem()
			compressor = fakecmd.NewFakeCompressor()
			logger := boshlog.NewLogger(boshlog.LevelNone)
			applier = NewRenderedJobApplier(
				jobsBc,
				jobSupervisor,
				packageApplierProvider,
				blobstore,
				compressor,
				fs,
				logger,
			)
		})

		Describe("Prepare & Apply", func() {
			var (
				job    models.Job
				bundle *fakebc.FakeBundle
			)

			BeforeEach(func() {
				job, bundle = buildJob(jobsBc)
			})

			ItInstallsJob := func(act func() error) {
				It("returns error when installing job fails", func() {
					bundle.InstallError = errors.New("fake-install-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-install-error"))
				})

				It("downloads and later cleans up downloaded job template blob", func() {
					blobstore.GetFileName = "/fake-blobstore-file-name"

					err := act()
					Expect(err).ToNot(HaveOccurred())
					Expect(blobstore.GetBlobIDs[0]).To(Equal("fake-blobstore-id"))
					Expect(blobstore.GetFingerprints[0]).To(Equal("fake-blob-sha1"))

					// downloaded file is cleaned up
					Expect(blobstore.CleanUpFileName).To(Equal("/fake-blobstore-file-name"))
				})

				It("returns error when downloading job template blob fails", func() {
					blobstore.GetError = errors.New("fake-get-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-get-error"))
				})

				It("decompresses job template blob to tmp path and later cleans it up", func() {
					fs.TempDirDir = "/fake-tmp-dir"
					blobstore.GetFileName = "/fake-blobstore-file-name"

					var tmpDirExistsBeforeInstall bool

					bundle.InstallCallBack = func() {
						tmpDirExistsBeforeInstall = true
					}

					err := act()
					Expect(err).ToNot(HaveOccurred())

					Expect(compressor.DecompressFileToDirTarballPaths[0]).To(Equal("/fake-blobstore-file-name"))
					Expect(compressor.DecompressFileToDirDirs[0]).To(Equal("/fake-tmp-dir"))

					// tmp dir exists before bundle install
					Expect(tmpDirExistsBeforeInstall).To(BeTrue())

					// tmp dir is cleaned up after install
					Expect(fs.FileExists(fs.TempDirDir)).To(BeFalse())
				})

				It("returns error when temporary directory creation fails", func() {
					fs.TempDirError = errors.New("fake-filesystem-tempdir-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-filesystem-tempdir-error"))
				})

				It("returns error when decompressing job template fails", func() {
					compressor.DecompressFileToDirErr = errors.New("fake-decompress-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-decompress-error"))
				})

				It("returns error when getting the list of bin files fails", func() {
					fs.GlobErr = errors.New("fake-glob-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-glob-error"))
				})

				It("returns error when changing permissions on bin files fails", func() {
					fs.TempDirDir = "/fake-tmp-dir"

					fs.SetGlob("/fake-tmp-dir/fake-path-in-archive/bin/*", []string{
						"/fake-tmp-dir/fake-path-in-archive/bin/test",
					})

					fs.ChmodErr = errors.New("fake-chmod-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-chmod-error"))
				})

				It("installs bundle from decompressed tmp path of a job template", func() {
					fs.TempDirDir = "/fake-tmp-dir"

					var installedBeforeDecompression bool

					compressor.DecompressFileToDirCallBack = func() {
						installedBeforeDecompression = bundle.Installed
					}

					err := act()
					Expect(err).ToNot(HaveOccurred())

					// bundle installation did not happen before decompression
					Expect(installedBeforeDecompression).To(BeFalse())

					// make sure that bundle install happened after decompression
					Expect(bundle.InstallSourcePath).To(Equal("/fake-tmp-dir/fake-path-in-archive"))
				})

				It("sets executable bit for files in bin", func() {
					fs.TempDirDir = "/fake-tmp-dir"

					compressor.DecompressFileToDirCallBack = func() {
						fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/bin/test1", []byte{})
						fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/bin/test2", []byte{})
						fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/config/test", []byte{})
					}

					fs.SetGlob("/fake-tmp-dir/fake-path-in-archive/bin/*", []string{
						"/fake-tmp-dir/fake-path-in-archive/bin/test1",
						"/fake-tmp-dir/fake-path-in-archive/bin/test2",
					})

					var binTest1Stats, binTest2Stats, configTestStats *fakesys.FakeFileStats

					bundle.InstallCallBack = func() {
						binTest1Stats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/bin/test1")
						binTest2Stats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/bin/test2")
						configTestStats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/config/test")
					}

					err := act()
					Expect(err).ToNot(HaveOccurred())

					// bin files are executable
					Expect(int(binTest1Stats.FileMode)).To(Equal(0755))
					Expect(int(binTest2Stats.FileMode)).To(Equal(0755))

					// non-bin files are not made executable
					Expect(int(configTestStats.FileMode)).ToNot(Equal(0755))
				})
			}

			ItUpdatesPackages := func(act func() error) {
				var packageApplier *fakepa.FakePackageApplier

				BeforeEach(func() {
					packageApplier = fakepa.NewFakePackageApplier()
					packageApplierProvider.JobSpecificPackageAppliers[job.Name] = packageApplier
				})

				It("applies each package that job depends on and then cleans up packages", func() {
					err := act()
					Expect(err).ToNot(HaveOccurred())
					Expect(packageApplier.ActionsCalled).To(Equal([]string{"Apply", "Apply", "KeepOnly"}))
					Expect(len(packageApplier.AppliedPackages)).To(Equal(2)) // present
					Expect(packageApplier.AppliedPackages).To(Equal(job.Packages))
				})

				It("returns error when applying package that job depends on fails", func() {
					packageApplier.ApplyError = errors.New("fake-apply-err")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-apply-err"))
				})

				It("keeps only currently required packages but does not completely uninstall them", func() {
					err := act()
					Expect(err).ToNot(HaveOccurred())
					Expect(len(packageApplier.KeptOnlyPackages)).To(Equal(2)) // present
					Expect(packageApplier.KeptOnlyPackages).To(Equal(job.Packages))
				})

				It("returns error when keeping only currently required packages fails", func() {
					packageApplier.KeepOnlyErr = errors.New("fake-keep-only-err")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-keep-only-err"))
				})
			}

			Describe("Prepare", func() {
				act := func() error { return applier.Prepare(job) }

				It("return an error if getting file bundle fails", func() {
					jobsBc.GetErr = errors.New("fake-get-bundle-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-get-bundle-error"))
				})

				It("returns an error if checking for installed path fails", func() {
					bundle.IsInstalledErr = errors.New("fake-is-installed-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-is-installed-error"))
				})

				Context("when job is already installed", func() {
					BeforeEach(func() {
						bundle.Installed = true
					})

					It("does not install", func() {
						err := act()
						Expect(err).ToNot(HaveOccurred())
						Expect(bundle.ActionsCalled).To(Equal([]string{})) // no Install
					})

					It("does not download the job template", func() {
						err := act()
						Expect(err).ToNot(HaveOccurred())
						Expect(blobstore.GetBlobIDs).To(BeNil())
					})
				})

				Context("when job is not installed", func() {
					BeforeEach(func() {
						bundle.Installed = false
					})

					It("installs job (but does not enable)", func() {
						err := act()
						Expect(err).ToNot(HaveOccurred())
						Expect(bundle.ActionsCalled).To(Equal([]string{"Install"}))
					})

					ItInstallsJob(act)
				})
			})

			Describe("Apply", func() {
				act := func() error { return applier.Apply(job) }

				It("return an error if getting file bundle fails", func() {
					jobsBc.GetErr = errors.New("fake-get-bundle-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-get-bundle-error"))
				})

				It("returns an error if checking for installed path fails", func() {
					bundle.IsInstalledErr = errors.New("fake-is-installed-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-is-installed-error"))
				})

				Context("when job is already installed", func() {
					BeforeEach(func() {
						bundle.Installed = true
					})

					It("does not install but only enables job", func() {
						err := act()
						Expect(err).ToNot(HaveOccurred())
						Expect(bundle.ActionsCalled).To(Equal([]string{"Enable"})) // no Install
					})

					It("returns error when job enable fails", func() {
						bundle.EnableError = errors.New("fake-enable-error")

						err := act()
						Expect(err).To(HaveOccurred())
						Expect(err.Error()).To(ContainSubstring("fake-enable-error"))
					})

					It("does not download the job template", func() {
						err := act()
						Expect(err).ToNot(HaveOccurred())
						Expect(blobstore.GetBlobIDs).To(BeNil())
					})

					ItUpdatesPackages(act)
				})

				Context("when job is not installed", func() {
					BeforeEach(func() {
						bundle.Installed = false
					})

					It("installs and enables job", func() {
						err := act()
						Expect(err).ToNot(HaveOccurred())
						Expect(bundle.ActionsCalled).To(Equal([]string{"Install", "Enable"}))
					})

					It("returns error when job enable fails", func() {
						bundle.EnableError = errors.New("fake-enable-error")

						err := act()
						Expect(err).To(HaveOccurred())
						Expect(err.Error()).To(ContainSubstring("fake-enable-error"))
					})

					ItInstallsJob(act)

					ItUpdatesPackages(act)
				})
			})
		})

		Describe("Configure", func() {
			It("adds job to the job supervisor", func() {
				job, bundle := buildJob(jobsBc)

				fs := fakesys.NewFakeFileSystem()
				fs.WriteFileString("/path/to/job/monit", "some conf")
				fs.SetGlob("/path/to/job/*.monit", []string{"/path/to/job/subjob.monit"})

				bundle.GetDirPath = "/path/to/job"
				bundle.GetDirFs = fs

				err := applier.Configure(job, 0)
				Expect(err).ToNot(HaveOccurred())

				Expect(2).To(Equal(len(jobSupervisor.AddJobArgs)))

				firstArgs := fakejobsuper.AddJobArgs{
					Name:       job.Name,
					Index:      0,
					ConfigPath: "/path/to/job/monit",
				}

				secondArgs := fakejobsuper.AddJobArgs{
					Name:       job.Name + "_subjob",
					Index:      0,
					ConfigPath: "/path/to/job/subjob.monit",
				}
				Expect(firstArgs).To(Equal(jobSupervisor.AddJobArgs[0]))
				Expect(secondArgs).To(Equal(jobSupervisor.AddJobArgs[1]))
			})
		})

		Describe("KeepOnly", func() {
			It("first disables and then uninstalls jobs that are not in keeponly list", func() {
				_, bundle1 := buildJob(jobsBc)
				job2, bundle2 := buildJob(jobsBc)
				_, bundle3 := buildJob(jobsBc)
				job4, bundle4 := buildJob(jobsBc)

				jobsBc.ListBundles = []boshbc.Bundle{bundle1, bundle2, bundle3, bundle4}

				err := applier.KeepOnly([]models.Job{job4, job2})
				Expect(err).ToNot(HaveOccurred())

				Expect(bundle1.ActionsCalled).To(Equal([]string{"Disable", "Uninstall"}))
				Expect(bundle2.ActionsCalled).To(Equal([]string{}))
				Expect(bundle3.ActionsCalled).To(Equal([]string{"Disable", "Uninstall"}))
				Expect(bundle4.ActionsCalled).To(Equal([]string{}))
			})

			It("returns error when bundle collection fails to return list of installed bundles", func() {
				jobsBc.ListErr = errors.New("fake-bc-list-error")

				err := applier.KeepOnly([]models.Job{})
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-bc-list-error"))
			})

			It("returns error when bundle collection cannot retrieve bundle for keep-only job", func() {
				job1, bundle1 := buildJob(jobsBc)

				jobsBc.ListBundles = []boshbc.Bundle{bundle1}
				jobsBc.GetErr = errors.New("fake-bc-get-error")

				err := applier.KeepOnly([]models.Job{job1})
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-bc-get-error"))
			})

			It("returns error when at least one bundle cannot be disabled", func() {
				_, bundle1 := buildJob(jobsBc)

				jobsBc.ListBundles = []boshbc.Bundle{bundle1}
				bundle1.DisableErr = errors.New("fake-bc-disable-error")

				err := applier.KeepOnly([]models.Job{})
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-bc-disable-error"))
			})

			It("returns error when at least one bundle cannot be uninstalled", func() {
				_, bundle1 := buildJob(jobsBc)

				jobsBc.ListBundles = []boshbc.Bundle{bundle1}
				bundle1.UninstallErr = errors.New("fake-bc-uninstall-error")

				err := applier.KeepOnly([]models.Job{})
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-bc-uninstall-error"))
			})
		})
	})
}
func init() {
	const expectedCentosDHCPConfig = `# Generated by bosh-agent

option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;

send host-name "<hostname>";

request subnet-mask, broadcast-address, time-offset, routers,
	domain-name, domain-name-servers, domain-search, host-name,
	netbios-name-servers, netbios-scope, interface-mtu,
	rfc3442-classless-static-routes, ntp-servers;

prepend domain-name-servers xx.xx.xx.xx;
prepend domain-name-servers yy.yy.yy.yy;
prepend domain-name-servers zz.zz.zz.zz;
`

	const expectedCentosIfcfg = `DEVICE=eth0
BOOTPROTO=static
IPADDR=192.168.195.6
NETMASK=255.255.255.0
BROADCAST=192.168.195.255
GATEWAY=192.168.195.1
ONBOOT=yes`

	Describe("centos", func() {
		var (
			fs                     *fakesys.FakeFileSystem
			cmdRunner              *fakesys.FakeCmdRunner
			defaultNetworkResolver *fakenet.FakeDefaultNetworkResolver
			ipResolver             *fakeip.FakeIPResolver
			addressBroadcaster     *fakearp.FakeAddressBroadcaster
			netManager             NetManager
		)

		BeforeEach(func() {
			fs = fakesys.NewFakeFileSystem()
			cmdRunner = fakesys.NewFakeCmdRunner()
			defaultNetworkResolver = &fakenet.FakeDefaultNetworkResolver{}
			ipResolver = &fakeip.FakeIPResolver{}
			addressBroadcaster = &fakearp.FakeAddressBroadcaster{}
			logger := boshlog.NewLogger(boshlog.LevelNone)
			netManager = NewCentosNetManager(
				fs,
				cmdRunner,
				defaultNetworkResolver,
				ipResolver,
				addressBroadcaster,
				logger,
			)
		})

		Describe("SetupDhcp", func() {
			networks := boshsettings.Networks{
				"bosh": boshsettings.Network{
					Default: []string{"dns"},
					DNS:     []string{"xx.xx.xx.xx", "yy.yy.yy.yy", "zz.zz.zz.zz"},
				},
				"vip": boshsettings.Network{
					Default: []string{},
					DNS:     []string{"aa.aa.aa.aa"},
				},
			}

			ItBroadcastsMACAddresses := func() {
				It("starts broadcasting the MAC addresses", func() {
					errCh := make(chan error)

					err := netManager.SetupDhcp(networks, errCh)
					Expect(err).ToNot(HaveOccurred())

					<-errCh // wait for all arpings

					Expect(addressBroadcaster.BroadcastMACAddressesAddresses).To(Equal(
						[]boship.InterfaceAddress{
							// Resolve IP address because IP may not be known
							boship.NewResolvingInterfaceAddress("eth0", ipResolver),
						},
					))
				})
			}

			Context("when dhcp was not previously configured", func() {
				It("writes dhcp configuration", func() {
					err := netManager.SetupDhcp(networks, nil)
					Expect(err).ToNot(HaveOccurred())

					dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf")
					Expect(dhcpConfig).ToNot(BeNil())
					Expect(dhcpConfig.StringContents()).To(Equal(expectedCentosDHCPConfig))
				})

				It("restarts network", func() {
					err := netManager.SetupDhcp(networks, nil)
					Expect(err).ToNot(HaveOccurred())

					Expect(len(cmdRunner.RunCommands)).To(Equal(1))
					Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network", "restart"}))
				})

				ItBroadcastsMACAddresses()
			})

			Context("when dhcp was previously configured with different configuration", func() {
				BeforeEach(func() {
					fs.WriteFileString("/etc/dhcp/dhclient.conf", "fake-other-configuration")
				})

				It("updates dhcp configuration", func() {
					err := netManager.SetupDhcp(networks, nil)
					Expect(err).ToNot(HaveOccurred())

					dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf")
					Expect(dhcpConfig).ToNot(BeNil())
					Expect(dhcpConfig.StringContents()).To(Equal(expectedCentosDHCPConfig))
				})

				It("restarts network", func() {
					err := netManager.SetupDhcp(networks, nil)
					Expect(err).ToNot(HaveOccurred())

					Expect(len(cmdRunner.RunCommands)).To(Equal(1))
					Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network", "restart"}))
				})

				ItBroadcastsMACAddresses()
			})

			Context("when dhcp was previously configured with same configuration", func() {
				BeforeEach(func() {
					fs.WriteFileString("/etc/dhcp/dhclient.conf", expectedCentosDHCPConfig)
				})

				It("keeps dhcp configuration", func() {
					err := netManager.SetupDhcp(networks, nil)
					Expect(err).ToNot(HaveOccurred())

					dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf")
					Expect(dhcpConfig).ToNot(BeNil())
					Expect(dhcpConfig.StringContents()).To(Equal(expectedCentosDHCPConfig))
				})

				It("does not restart network", func() {
					err := netManager.SetupDhcp(networks, nil)
					Expect(err).ToNot(HaveOccurred())

					Expect(len(cmdRunner.RunCommands)).To(Equal(0))
				})

				ItBroadcastsMACAddresses()
			})
		})

		Describe("SetupManualNetworking", func() {
			var errCh chan error

			BeforeEach(func() {
				errCh = make(chan error)
			})

			BeforeEach(func() {
				fs.WriteFileString("/sys/class/net/eth0/address", "22:00:0a:1f:ac:2a\n")
				fs.SetGlob("/sys/class/net/*", []string{"/sys/class/net/eth0"})
			})

			networks := boshsettings.Networks{
				"bosh": boshsettings.Network{
					Default: []string{"dns", "gateway"},
					IP:      "192.168.195.6",
					Netmask: "255.255.255.0",
					Gateway: "192.168.195.1",
					Mac:     "22:00:0a:1f:ac:2a",
					DNS:     []string{"10.80.130.1", "10.80.130.2"},
				},
			}

			It("sets up centos expected ifconfig", func() {
				err := netManager.SetupManualNetworking(networks, nil)
				Expect(err).ToNot(HaveOccurred())

				networkConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-eth0")
				Expect(networkConfig).ToNot(BeNil())
				Expect(networkConfig.StringContents()).To(Equal(expectedCentosIfcfg))
			})

			It("sets up centos /etc/resolv.conf", func() {
				err := netManager.SetupManualNetworking(networks, nil)
				Expect(err).ToNot(HaveOccurred())

				resolvConf := fs.GetFileTestStat("/etc/resolv.conf")
				Expect(resolvConf).ToNot(BeNil())
				Expect(resolvConf.StringContents()).To(Equal(expectedCentosResolvConf))
			})

			It("restarts networking", func() {
				err := netManager.SetupManualNetworking(networks, errCh)
				Expect(err).ToNot(HaveOccurred())

				fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-eth0")
				fs.GetFileTestStat("/etc/resolv.conf")

				<-errCh // wait for all arpings

				Expect(len(cmdRunner.RunCommands)).To(Equal(1))
				Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network", "restart"}))
			})

			It("starts broadcasting the MAC addresses", func() {
				err := netManager.SetupManualNetworking(networks, errCh)
				Expect(err).ToNot(HaveOccurred())

				fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-eth0")
				fs.GetFileTestStat("/etc/resolv.conf")

				<-errCh // wait for all arpings

				Expect(addressBroadcaster.BroadcastMACAddressesAddresses).To(Equal([]boship.InterfaceAddress{
					boship.NewSimpleInterfaceAddress("eth0", "192.168.195.6"),
				}))
			})
		})
	})
}