func (s Fetcher) GetStemcell(deploymentManifest bideplmanifest.Manifest, stage biui.Stage) (ExtractedStemcell, error) { stemcell, err := deploymentManifest.Stemcell(deploymentManifest.JobName()) if err != nil { return nil, err } stemcellTarballPath, err := s.TarballProvider.Get(stemcell, stage) if err != nil { return nil, err } var extractedStemcell ExtractedStemcell err = stage.Perform("Validating stemcell", func() error { extractedStemcell, err = s.StemcellExtractor.Extract(stemcellTarballPath) if err != nil { return bosherr.WrapErrorf(err, "Extracting stemcell from '%s'", stemcellTarballPath) } return nil }) if err != nil { return nil, err } return extractedStemcell, nil }
func (b *builder) BuildInitialState(jobName string, instanceID int, deploymentManifest bideplmanifest.Manifest) (State, error) { deploymentJob, found := deploymentManifest.FindJobByName(jobName) if !found { return nil, bosherr.Errorf("Job '%s' not found in deployment manifest", jobName) } networkInterfaces, err := deploymentManifest.NetworkInterfaces(deploymentJob.Name) if err != nil { return nil, bosherr.WrapErrorf(err, "Finding networks for job '%s", jobName) } // convert map to array networkRefs := make([]NetworkRef, 0, len(networkInterfaces)) for networkName, networkInterface := range networkInterfaces { genericMap := make(map[string]interface{}, len(networkInterface)) for k, v := range networkInterface { genericMap[k] = v } networkRefs = append(networkRefs, NetworkRef{ Name: networkName, Interface: genericMap, }) } return &state{ deploymentName: deploymentManifest.Name, name: jobName, id: instanceID, networks: networkRefs, }, nil }
func (i *instance) UpdateDisks(deploymentManifest bideplmanifest.Manifest, stage biui.Stage) ([]bidisk.Disk, error) { diskPool, err := deploymentManifest.DiskPool(i.jobName) if err != nil { return []bidisk.Disk{}, bosherr.WrapError(err, "Getting disk pool") } disks, err := i.vm.UpdateDisks(diskPool, stage) if err != nil { return disks, bosherr.WrapError(err, "Updating disks") } return disks, nil }
func (m *manager) Create(stemcell bistemcell.CloudStemcell, deploymentManifest bideplmanifest.Manifest) (VM, error) { jobName := deploymentManifest.JobName() networkInterfaces, err := deploymentManifest.NetworkInterfaces(jobName) m.logger.Debug(m.logTag, "Creating VM with network interfaces: %#v", networkInterfaces) if err != nil { return nil, bosherr.WrapError(err, "Getting network spec") } resourcePool, err := deploymentManifest.ResourcePool(jobName) if err != nil { return nil, bosherr.WrapErrorf(err, "Getting resource pool for job '%s'", jobName) } agentID, err := m.uuidGenerator.Generate() if err != nil { return nil, bosherr.WrapError(err, "Generating agent ID") } cid, err := m.createAndRecordVm(agentID, stemcell, resourcePool, networkInterfaces) if err != nil { return nil, err } metadata := bicloud.VMMetadata{ Deployment: deploymentManifest.Name, Job: deploymentManifest.JobName(), Index: "0", Director: "bosh-init", } err = m.cloud.SetVMMetadata(cid, metadata) if err != nil { cloudErr, ok := err.(bicloud.Error) if ok && cloudErr.Type() == bicloud.NotImplementedError { //ignore it } else { return nil, bosherr.WrapErrorf(err, "Setting VM metadata to %s", metadata) } } vm := NewVM( cid, m.vmRepo, m.stemcellRepo, m.diskDeployer, m.agentClient, m.cloud, m.fs, m.logger, ) return vm, nil }
func (b *builder) Build(jobName string, instanceID int, deploymentManifest bideplmanifest.Manifest, stage biui.Stage) (State, error) { deploymentJob, found := deploymentManifest.FindJobByName(jobName) if !found { return nil, bosherr.Errorf("Job '%s' not found in deployment manifest", jobName) } releaseJobs, err := b.resolveJobs(deploymentJob.Templates) if err != nil { return nil, bosherr.WrapErrorf(err, "Resolving jobs for instance '%s/%d'", jobName, instanceID) } renderedJobTemplates, err := b.renderJobTemplates(releaseJobs, deploymentJob.Properties, deploymentManifest.Properties, deploymentManifest.Name, stage) if err != nil { return nil, bosherr.WrapErrorf(err, "Rendering job templates for instance '%s/%d'", jobName, instanceID) } compiledPackageRefs, err := b.jobDependencyCompiler.Compile(releaseJobs, stage) if err != nil { return nil, bosherr.WrapErrorf(err, "Compiling job package dependencies for instance '%s/%d'", jobName, instanceID) } networkInterfaces, err := deploymentManifest.NetworkInterfaces(deploymentJob.Name) if err != nil { return nil, bosherr.WrapErrorf(err, "Finding networks for job '%s", jobName) } // convert map to array networkRefs := make([]NetworkRef, 0, len(networkInterfaces)) for networkName, networkInterface := range networkInterfaces { networkRefs = append(networkRefs, NetworkRef{ Name: networkName, Interface: networkInterface, }) } compiledDeploymentPackageRefs := make([]PackageRef, len(compiledPackageRefs), len(compiledPackageRefs)) for i, compiledPackageRef := range compiledPackageRefs { compiledDeploymentPackageRefs[i] = PackageRef{ Name: compiledPackageRef.Name, Version: compiledPackageRef.Version, Archive: BlobRef{ BlobstoreID: compiledPackageRef.BlobstoreID, SHA1: compiledPackageRef.SHA1, }, } } // convert array to array renderedJobRefs := make([]JobRef, len(releaseJobs), len(releaseJobs)) for i, releaseJob := range releaseJobs { renderedJobRefs[i] = JobRef{ Name: releaseJob.Name, Version: releaseJob.Fingerprint, } } renderedJobListArchiveBlobRef := BlobRef{ BlobstoreID: renderedJobTemplates.BlobstoreID, SHA1: renderedJobTemplates.Archive.SHA1(), } return &state{ deploymentName: deploymentManifest.Name, name: jobName, id: instanceID, networks: networkRefs, compiledPackages: compiledDeploymentPackageRefs, renderedJobs: renderedJobRefs, renderedJobListArchive: renderedJobListArchiveBlobRef, hash: renderedJobTemplates.Archive.Fingerprint(), }, nil }
func (c *DeploymentPreparer) PrepareDeployment(stage biui.Stage) (err error) { c.ui.PrintLinef("Deployment state: '%s'", c.deploymentStateService.Path()) if !c.deploymentStateService.Exists() { migrated, err := c.legacyDeploymentStateMigrator.MigrateIfExists(biconfig.LegacyDeploymentStatePath(c.deploymentManifestPath)) if err != nil { return bosherr.WrapError(err, "Migrating legacy deployment state file") } if migrated { c.ui.PrintLinef("Migrated legacy deployments file: '%s'", biconfig.LegacyDeploymentStatePath(c.deploymentManifestPath)) } } deploymentState, err := c.deploymentStateService.Load() if err != nil { return bosherr.WrapError(err, "Loading deployment state") } target, err := c.targetProvider.NewTarget() if err != nil { return bosherr.WrapError(err, "Determining installation target") } err = c.tempRootConfigurator.PrepareAndSetTempRoot(target.TmpPath(), c.logger) if err != nil { return bosherr.WrapError(err, "Setting temp root") } defer func() { err := c.releaseManager.DeleteAll() if err != nil { c.logger.Warn(c.logTag, "Deleting all extracted releases: %s", err.Error()) } }() var ( extractedStemcell bistemcell.ExtractedStemcell deploymentManifest bideplmanifest.Manifest installationManifest biinstallmanifest.Manifest ) err = stage.PerformComplex("validating", func(stage biui.Stage) error { var releaseSetManifest birelsetmanifest.Manifest releaseSetManifest, installationManifest, err = c.releaseSetAndInstallationManifestParser.ReleaseSetAndInstallationManifest(c.deploymentManifestPath) if err != nil { return err } for _, releaseRef := range releaseSetManifest.Releases { err = c.releaseFetcher.DownloadAndExtract(releaseRef, stage) if err != nil { return err } } err := c.cpiInstaller.ValidateCpiRelease(installationManifest, stage) if err != nil { return err } deploymentManifest, err = c.deploymentManifestParser.GetDeploymentManifest(c.deploymentManifestPath, releaseSetManifest, stage) if err != nil { return err } extractedStemcell, err = c.stemcellFetcher.GetStemcell(deploymentManifest, stage) nonCpiReleasesMap, _ := deploymentManifest.GetListOfTemplateReleases() delete(nonCpiReleasesMap, installationManifest.Template.Release) // remove CPI release from nonCpiReleasesMap for _, release := range c.releaseManager.List() { if _, ok := nonCpiReleasesMap[release.Name()]; ok { if release.IsCompiled() { compilationOsAndVersion := release.Packages()[0].Stemcell if strings.ToLower(compilationOsAndVersion) != strings.ToLower(extractedStemcell.OsAndVersion()) { return bosherr.Errorf("OS/Version mismatch between deployment stemcell and compiled package stemcell for release '%s'", release.Name()) } } } else { // It is a CPI release, check if it is compiled if release.IsCompiled() { return bosherr.Errorf("CPI is not allowed to be a compiled release. The provided CPI release '%s' is compiled", release.Name()) } } } return err }) if err != nil { return err } defer func() { deleteErr := extractedStemcell.Delete() if deleteErr != nil { c.logger.Warn(c.logTag, "Failed to delete extracted stemcell: %s", deleteErr.Error()) } }() isDeployed, err := c.deploymentRecord.IsDeployed(c.deploymentManifestPath, c.releaseManager.List(), extractedStemcell) if err != nil { return bosherr.WrapError(err, "Checking if deployment has changed") } if isDeployed { c.ui.PrintLinef("No deployment, stemcell or release changes. Skipping deploy.") return nil } err = c.cpiInstaller.WithInstalledCpiRelease(installationManifest, target, stage, func(installation biinstall.Installation) error { return installation.WithRunningRegistry(c.logger, stage, func() error { return c.deploy( installation, deploymentState, extractedStemcell, installationManifest, deploymentManifest, stage) }) }) return err }
func (m *manager) Create(stemcell bistemcell.CloudStemcell, deploymentManifest bideplmanifest.Manifest) (VM, error) { jobName := deploymentManifest.JobName() networkInterfaces, err := deploymentManifest.NetworkInterfaces(jobName) m.logger.Debug(m.logTag, "Creating VM with network interfaces: %#v", networkInterfaces) if err != nil { return nil, bosherr.WrapError(err, "Getting network spec") } resourcePool, err := deploymentManifest.ResourcePool(jobName) if err != nil { return nil, bosherr.WrapErrorf(err, "Getting resource pool for job '%s'", jobName) } agentID, found, err := m.vmRepo.FindCurrentAgentId() if err != nil { return nil, bosherr.WrapError(err, "Finding currently agent id of deployed vm") } if !found { agentID, err = m.uuidGenerator.Generate() if err != nil { return nil, bosherr.WrapError(err, "Generating agent ID") } } currentIP, found, err := m.vmRepo.FindCurrentIP() if err != nil { return nil, bosherr.WrapError(err, "Finding currently IP address of deployed vm") } ifaceMap := map[string]biproperty.Map{} if found { for networkName, networkInterface := range networkInterfaces { networkInterface["ip"] = currentIP ifaceMap[networkName] = networkInterface } } else { ifaceMap = networkInterfaces } cid, err := m.createAndRecordVm(agentID, stemcell, resourcePool, ifaceMap) if err != nil { return nil, err } metadata := bicloud.VMMetadata{ Deployment: deploymentManifest.Name, Job: deploymentManifest.JobName(), Index: "0", Director: "bosh-init", } err = m.cloud.SetVMMetadata(cid, metadata) if err != nil { cloudErr, ok := err.(bicloud.Error) if ok && cloudErr.Type() == bicloud.NotImplementedError { //ignore it } else { return nil, bosherr.WrapErrorf(err, "Setting VM metadata to %s", metadata) } } vm := NewVM( cid, m.vmRepo, m.stemcellRepo, m.diskDeployer, m.agentClient, m.cloud, m.fs, m.logger, ) return vm, nil }
func (b *builder) Build(jobName string, instanceID int, deploymentManifest bideplmanifest.Manifest, stage biui.Stage, agentState agentclient.AgentState) (State, error) { initialState, err := b.BuildInitialState(jobName, instanceID, deploymentManifest) if err != nil { return nil, bosherr.WrapErrorf(err, "Building initial state '%s", jobName) } deploymentJob, found := deploymentManifest.FindJobByName(jobName) if !found { return nil, bosherr.Errorf("Job '%s' not found in deployment manifest", jobName) } releaseJobs, err := b.resolveJobs(deploymentJob.Templates) if err != nil { return nil, bosherr.WrapErrorf(err, "Resolving jobs for instance '%s/%d'", jobName, instanceID) } releaseJobProperties := make(map[string]*biproperty.Map) for _, releaseJob := range deploymentJob.Templates { releaseJobProperties[releaseJob.Name] = releaseJob.Properties } defaultAddress, err := b.defaultAddress(initialState.NetworkInterfaces(), agentState) if err != nil { return nil, err } renderedJobTemplates, err := b.renderJobTemplates(releaseJobs, releaseJobProperties, deploymentJob.Properties, deploymentManifest.Properties, deploymentManifest.Name, defaultAddress, stage) if err != nil { return nil, bosherr.WrapErrorf(err, "Rendering job templates for instance '%s/%d'", jobName, instanceID) } compiledPackageRefs, err := b.jobDependencyCompiler.Compile(releaseJobs, stage) if err != nil { return nil, bosherr.WrapErrorf(err, "Compiling job package dependencies for instance '%s/%d'", jobName, instanceID) } compiledDeploymentPackageRefs := make([]PackageRef, len(compiledPackageRefs), len(compiledPackageRefs)) for i, compiledPackageRef := range compiledPackageRefs { compiledDeploymentPackageRefs[i] = PackageRef{ Name: compiledPackageRef.Name, Version: compiledPackageRef.Version, Archive: BlobRef{ BlobstoreID: compiledPackageRef.BlobstoreID, SHA1: compiledPackageRef.SHA1, }, } } // convert array to array renderedJobRefs := make([]JobRef, len(releaseJobs), len(releaseJobs)) for i, releaseJob := range releaseJobs { renderedJobRefs[i] = JobRef{ Name: releaseJob.Name, Version: releaseJob.Fingerprint, } } renderedJobListArchiveBlobRef := BlobRef{ BlobstoreID: renderedJobTemplates.BlobstoreID, SHA1: renderedJobTemplates.Archive.SHA1(), } return &state{ deploymentName: deploymentManifest.Name, name: jobName, id: instanceID, networks: initialState.NetworkInterfaces(), compiledPackages: compiledDeploymentPackageRefs, renderedJobs: renderedJobRefs, renderedJobListArchive: renderedJobListArchiveBlobRef, hash: renderedJobTemplates.Archive.Fingerprint(), }, nil }
func describeBuilder() { var mockCtrl *gomock.Controller BeforeEach(func() { mockCtrl = gomock.NewController(GinkgoT()) }) AfterEach(func() { mockCtrl.Finish() }) var ( logger boshlog.Logger mockReleaseJobResolver *mock_deployment_release.MockJobResolver mockDependencyCompiler *mock_state_job.MockDependencyCompiler mockJobListRenderer *mock_template.MockJobListRenderer mockCompressor *mock_template.MockRenderedJobListCompressor mockBlobstore *mock_blobstore.MockBlobstore stateBuilder Builder ) BeforeEach(func() { logger = boshlog.NewLogger(boshlog.LevelNone) mockReleaseJobResolver = mock_deployment_release.NewMockJobResolver(mockCtrl) mockDependencyCompiler = mock_state_job.NewMockDependencyCompiler(mockCtrl) mockJobListRenderer = mock_template.NewMockJobListRenderer(mockCtrl) mockCompressor = mock_template.NewMockRenderedJobListCompressor(mockCtrl) mockBlobstore = mock_blobstore.NewMockBlobstore(mockCtrl) }) Describe("BuildInitialState", func() { var ( jobName string instanceID int deploymentManifest bideplmanifest.Manifest ) BeforeEach(func() { jobName = "fake-deployment-job-name" instanceID = 0 deploymentManifest = bideplmanifest.Manifest{ Name: "fake-deployment-name", Jobs: []bideplmanifest.Job{ { Name: "fake-deployment-job-name", Networks: []bideplmanifest.JobNetwork{ { Name: "fake-network-name", StaticIPs: []string{"1.2.3.4"}, }, }, Templates: []bideplmanifest.ReleaseJobRef{ { Name: "fake-release-job-name", Release: "fake-release-name", Properties: &biproperty.Map{ "fake-template-property": "fake-template-property-value", }, }, }, Properties: biproperty.Map{ "fake-job-property": "fake-job-property-value", }, }, }, Networks: []bideplmanifest.Network{ { Name: "fake-network-name", Type: "fake-network-type", CloudProperties: biproperty.Map{ "fake-network-cloud-property": "fake-network-cloud-property-value", }, }, }, Properties: biproperty.Map{ "fake-job-property": "fake-global-property-value", //overridden by job property value }, } stateBuilder = NewBuilder( mockReleaseJobResolver, mockDependencyCompiler, mockJobListRenderer, mockCompressor, mockBlobstore, logger, ) }) It("generates an initial apply spec", func() { state, err := stateBuilder.BuildInitialState(jobName, instanceID, deploymentManifest) Expect(err).ToNot(HaveOccurred()) Expect(state.ToApplySpec()).To(Equal(bias.ApplySpec{ Deployment: "fake-deployment-name", Index: 0, Job: bias.Job{ Name: "fake-deployment-job-name", Templates: []bias.Blob{}, }, Packages: map[string]bias.Blob{}, Networks: map[string]interface{}{ "fake-network-name": map[string]interface{}{ "type": "fake-network-type", "default": []bideplmanifest.NetworkDefault{"dns", "gateway"}, "ip": "1.2.3.4", "cloud_properties": biproperty.Map{ "fake-network-cloud-property": "fake-network-cloud-property-value", }, }, }, })) }) }) Describe("Build", func() { var ( mockRenderedJobList *mock_template.MockRenderedJobList mockRenderedJobListArchive *mock_template.MockRenderedJobListArchive jobName string instanceID int deploymentManifest bideplmanifest.Manifest fakeStage *fakebiui.FakeStage releasePackageLibyaml *birelpkg.Package releasePackageRuby *birelpkg.Package releasePackageCPI *birelpkg.Package agentState biac.AgentState expectedIP string expectCompile *gomock.Call ) BeforeEach(func() { mockRenderedJobList = mock_template.NewMockRenderedJobList(mockCtrl) mockRenderedJobListArchive = mock_template.NewMockRenderedJobListArchive(mockCtrl) jobName = "fake-deployment-job-name" instanceID = 0 expectedIP = "1.2.3.4" deploymentManifest = bideplmanifest.Manifest{ Name: "fake-deployment-name", Jobs: []bideplmanifest.Job{ { Name: "fake-deployment-job-name", Networks: []bideplmanifest.JobNetwork{ { Name: "fake-network-name", StaticIPs: []string{"1.2.3.4"}, }, }, Templates: []bideplmanifest.ReleaseJobRef{ { Name: "fake-release-job-name", Release: "fake-release-name", Properties: &biproperty.Map{ "fake-template-property": "fake-template-property-value", }, }, }, Properties: biproperty.Map{ "fake-job-property": "fake-job-property-value", }, }, }, Networks: []bideplmanifest.Network{ { Name: "fake-network-name", Type: "fake-network-type", CloudProperties: biproperty.Map{ "fake-network-cloud-property": "fake-network-cloud-property-value", }, }, }, Properties: biproperty.Map{ "fake-job-property": "fake-global-property-value", //overridden by job property value }, } agentState = biac.AgentState{ NetworkSpecs: map[string]biac.NetworkSpec{ "fake-network-name": biac.NetworkSpec{ IP: "1.2.3.5", }, }, } fakeStage = fakebiui.NewFakeStage() stateBuilder = NewBuilder( mockReleaseJobResolver, mockDependencyCompiler, mockJobListRenderer, mockCompressor, mockBlobstore, logger, ) releasePackageLibyaml = &birelpkg.Package{ Name: "libyaml", Fingerprint: "fake-package-source-fingerprint-libyaml", SHA1: "fake-package-source-sha1-libyaml", Dependencies: []*birelpkg.Package{}, ArchivePath: "fake-package-archive-path-libyaml", // only required by compiler... } releasePackageRuby = &birelpkg.Package{ Name: "ruby", Fingerprint: "fake-package-source-fingerprint-ruby", SHA1: "fake-package-source-sha1-ruby", Dependencies: []*birelpkg.Package{releasePackageLibyaml}, ArchivePath: "fake-package-archive-path-ruby", // only required by compiler... } releasePackageCPI = &birelpkg.Package{ Name: "cpi", Fingerprint: "fake-package-source-fingerprint-cpi", SHA1: "fake-package-source-sha1-cpi", Dependencies: []*birelpkg.Package{releasePackageRuby}, ArchivePath: "fake-package-archive-path-cpi", // only required by compiler... } }) JustBeforeEach(func() { releaseJob := bireljob.Job{ Name: "fake-release-job-name", Fingerprint: "fake-release-job-source-fingerprint", Packages: []*birelpkg.Package{releasePackageCPI, releasePackageRuby}, } mockReleaseJobResolver.EXPECT().Resolve("fake-release-job-name", "fake-release-name").Return(releaseJob, nil) releaseJobs := []bireljob.Job{releaseJob} compiledPackageRefs := []bistatejob.CompiledPackageRef{ { Name: "libyaml", Version: "fake-package-source-fingerprint-libyaml", BlobstoreID: "fake-package-compiled-archive-blob-id-libyaml", SHA1: "fake-package-compiled-archive-sha1-libyaml", }, { Name: "ruby", Version: "fake-package-source-fingerprint-ruby", BlobstoreID: "fake-package-compiled-archive-blob-id-ruby", SHA1: "fake-package-compiled-archive-sha1-ruby", }, { Name: "cpi", Version: "fake-package-source-fingerprint-cpi", BlobstoreID: "fake-package-compiled-archive-blob-id-cpi", SHA1: "fake-package-compiled-archive-sha1-cpi", }, } expectCompile = mockDependencyCompiler.EXPECT().Compile(releaseJobs, fakeStage).Return(compiledPackageRefs, nil).AnyTimes() releaseJobProperties := map[string]*biproperty.Map{ "fake-release-job-name": &biproperty.Map{ "fake-template-property": "fake-template-property-value", }, } jobProperties := biproperty.Map{ "fake-job-property": "fake-job-property-value", } globalProperties := biproperty.Map{ "fake-job-property": "fake-global-property-value", } mockJobListRenderer.EXPECT().Render(releaseJobs, releaseJobProperties, jobProperties, globalProperties, "fake-deployment-name", expectedIP).Return(mockRenderedJobList, nil) mockRenderedJobList.EXPECT().DeleteSilently() mockCompressor.EXPECT().Compress(mockRenderedJobList).Return(mockRenderedJobListArchive, nil) mockRenderedJobListArchive.EXPECT().DeleteSilently() mockRenderedJobListArchive.EXPECT().Path().Return("fake-rendered-job-list-archive-path") mockRenderedJobListArchive.EXPECT().SHA1().Return("fake-rendered-job-list-archive-sha1") mockRenderedJobListArchive.EXPECT().Fingerprint().Return("fake-rendered-job-list-fingerprint") mockBlobstore.EXPECT().Add("fake-rendered-job-list-archive-path").Return("fake-rendered-job-list-archive-blob-id", nil) }) It("compiles the dependencies of the jobs", func() { expectCompile.Times(1) _, err := stateBuilder.Build(jobName, instanceID, deploymentManifest, fakeStage, agentState) Expect(err).ToNot(HaveOccurred()) }) It("builds a new instance state with zero-to-many networks", func() { state, err := stateBuilder.Build(jobName, instanceID, deploymentManifest, fakeStage, agentState) Expect(err).ToNot(HaveOccurred()) Expect(state.NetworkInterfaces()).To(ContainElement(NetworkRef{ Name: "fake-network-name", Interface: map[string]interface{}{ "type": "fake-network-type", "default": []bideplmanifest.NetworkDefault{"dns", "gateway"}, "ip": "1.2.3.4", "cloud_properties": biproperty.Map{ "fake-network-cloud-property": "fake-network-cloud-property-value", }, }, })) Expect(state.NetworkInterfaces()).To(HaveLen(1)) }) Context("dynamic network without IP address", func() { Context("single network", func() { BeforeEach(func() { deploymentManifest.Jobs[0].Networks[0].StaticIPs = nil deploymentManifest.Networks[0].Type = "dynamic" expectedIP = "1.2.3.5" }) It("should not fail", func() { state, err := stateBuilder.Build(jobName, instanceID, deploymentManifest, fakeStage, agentState) Expect(err).ToNot(HaveOccurred()) Expect(state.NetworkInterfaces()).To(ContainElement(NetworkRef{ Name: "fake-network-name", Interface: map[string]interface{}{ "type": "dynamic", "default": []bideplmanifest.NetworkDefault{"dns", "gateway"}, "cloud_properties": biproperty.Map{ "fake-network-cloud-property": "fake-network-cloud-property-value", }, }, })) Expect(state.NetworkInterfaces()).To(HaveLen(1)) }) }) Context("multiple networks", func() { BeforeEach(func() { expectedIP = "1.2.3.6" deploymentManifest.Networks = append( deploymentManifest.Networks, bideplmanifest.Network{ Name: "fake-dynamic-network-name", Type: "dynamic", CloudProperties: biproperty.Map{ "fake-network-cloud-property": "fake-network-cloud-property-value", }, }, ) deploymentManifest.Jobs[0].Networks = append( deploymentManifest.Jobs[0].Networks, bideplmanifest.JobNetwork{ Name: "fake-dynamic-network-name", Defaults: []bideplmanifest.NetworkDefault{bideplmanifest.NetworkDefaultDNS, bideplmanifest.NetworkDefaultGateway}, }, ) agentState.NetworkSpecs["fake-dynamic-network-name"] = biac.NetworkSpec{ IP: "1.2.3.6", } }) It("should not fail", func() { state, err := stateBuilder.Build(jobName, instanceID, deploymentManifest, fakeStage, agentState) Expect(err).ToNot(HaveOccurred()) Expect(state.NetworkInterfaces()).To(ContainElement(NetworkRef{ Name: "fake-dynamic-network-name", Interface: map[string]interface{}{ "type": "dynamic", "default": []bideplmanifest.NetworkDefault{"dns", "gateway"}, "cloud_properties": biproperty.Map{ "fake-network-cloud-property": "fake-network-cloud-property-value", }, }, })) Expect(state.NetworkInterfaces()).To(HaveLen(2)) }) }) }) It("builds a new instance state with zero-to-many rendered jobs from one or more releases", func() { state, err := stateBuilder.Build(jobName, instanceID, deploymentManifest, fakeStage, agentState) Expect(err).ToNot(HaveOccurred()) Expect(state.RenderedJobs()).To(ContainElement(JobRef{ Name: "fake-release-job-name", Version: "fake-release-job-source-fingerprint", })) // multiple jobs are rendered in a single archive Expect(state.RenderedJobListArchive()).To(Equal(BlobRef{ BlobstoreID: "fake-rendered-job-list-archive-blob-id", SHA1: "fake-rendered-job-list-archive-sha1", })) Expect(state.RenderedJobs()).To(HaveLen(1)) }) It("prints ui stages for compiling packages and rendering job templates", func() { _, err := stateBuilder.Build(jobName, instanceID, deploymentManifest, fakeStage, agentState) Expect(err).ToNot(HaveOccurred()) Expect(fakeStage.PerformCalls).To(Equal([]*fakebiui.PerformCall{ // compile stages not produced by mockDependencyCompiler {Name: "Rendering job templates"}, })) }) It("builds a new instance state with the compiled packages required by the release jobs", func() { state, err := stateBuilder.Build(jobName, instanceID, deploymentManifest, fakeStage, agentState) Expect(err).ToNot(HaveOccurred()) Expect(state.CompiledPackages()).To(ContainElement(PackageRef{ Name: "cpi", Version: "fake-package-source-fingerprint-cpi", Archive: BlobRef{ SHA1: "fake-package-compiled-archive-sha1-cpi", BlobstoreID: "fake-package-compiled-archive-blob-id-cpi", }, })) Expect(state.CompiledPackages()).To(ContainElement(PackageRef{ Name: "ruby", Version: "fake-package-source-fingerprint-ruby", Archive: BlobRef{ SHA1: "fake-package-compiled-archive-sha1-ruby", BlobstoreID: "fake-package-compiled-archive-blob-id-ruby", }, })) }) It("builds a new instance state that includes transitively dependent compiled packages", func() { state, err := stateBuilder.Build(jobName, instanceID, deploymentManifest, fakeStage, agentState) Expect(err).ToNot(HaveOccurred()) Expect(state.CompiledPackages()).To(ContainElement(PackageRef{ Name: "cpi", Version: "fake-package-source-fingerprint-cpi", Archive: BlobRef{ SHA1: "fake-package-compiled-archive-sha1-cpi", BlobstoreID: "fake-package-compiled-archive-blob-id-cpi", }, })) Expect(state.CompiledPackages()).To(ContainElement(PackageRef{ Name: "ruby", Version: "fake-package-source-fingerprint-ruby", Archive: BlobRef{ SHA1: "fake-package-compiled-archive-sha1-ruby", BlobstoreID: "fake-package-compiled-archive-blob-id-ruby", }, })) Expect(state.CompiledPackages()).To(ContainElement(PackageRef{ Name: "libyaml", Version: "fake-package-source-fingerprint-libyaml", Archive: BlobRef{ SHA1: "fake-package-compiled-archive-sha1-libyaml", BlobstoreID: "fake-package-compiled-archive-blob-id-libyaml", }, })) Expect(state.CompiledPackages()).To(HaveLen(3)) }) Context("when multiple packages have the same dependency", func() { BeforeEach(func() { releasePackageRuby.Dependencies = append(releasePackageRuby.Dependencies, releasePackageLibyaml) }) It("does not recompile dependant packages", func() { state, err := stateBuilder.Build(jobName, instanceID, deploymentManifest, fakeStage, agentState) Expect(err).ToNot(HaveOccurred()) Expect(state.CompiledPackages()).To(ContainElement(PackageRef{ Name: "cpi", Version: "fake-package-source-fingerprint-cpi", Archive: BlobRef{ SHA1: "fake-package-compiled-archive-sha1-cpi", BlobstoreID: "fake-package-compiled-archive-blob-id-cpi", }, })) Expect(state.CompiledPackages()).To(ContainElement(PackageRef{ Name: "ruby", Version: "fake-package-source-fingerprint-ruby", Archive: BlobRef{ SHA1: "fake-package-compiled-archive-sha1-ruby", BlobstoreID: "fake-package-compiled-archive-blob-id-ruby", }, })) Expect(state.CompiledPackages()).To(ContainElement(PackageRef{ Name: "libyaml", Version: "fake-package-source-fingerprint-libyaml", Archive: BlobRef{ SHA1: "fake-package-compiled-archive-sha1-libyaml", BlobstoreID: "fake-package-compiled-archive-blob-id-libyaml", }, })) Expect(state.CompiledPackages()).To(HaveLen(3)) }) }) It("builds an instance state that can be converted to an ApplySpec", func() { state, err := stateBuilder.Build(jobName, instanceID, deploymentManifest, fakeStage, agentState) Expect(err).ToNot(HaveOccurred()) Expect(state.ToApplySpec()).To(Equal(bias.ApplySpec{ Deployment: "fake-deployment-name", Index: 0, Networks: map[string]interface{}{ "fake-network-name": map[string]interface{}{ "type": "fake-network-type", "default": []bideplmanifest.NetworkDefault{"dns", "gateway"}, "ip": "1.2.3.4", "cloud_properties": biproperty.Map{ "fake-network-cloud-property": "fake-network-cloud-property-value", }, }, }, Job: bias.Job{ Name: "fake-deployment-job-name", Templates: []bias.Blob{ { Name: "fake-release-job-name", Version: "fake-release-job-source-fingerprint", }, }, }, Packages: map[string]bias.Blob{ "cpi": bias.Blob{ Name: "cpi", Version: "fake-package-source-fingerprint-cpi", SHA1: "fake-package-compiled-archive-sha1-cpi", BlobstoreID: "fake-package-compiled-archive-blob-id-cpi", }, "ruby": bias.Blob{ Name: "ruby", Version: "fake-package-source-fingerprint-ruby", SHA1: "fake-package-compiled-archive-sha1-ruby", BlobstoreID: "fake-package-compiled-archive-blob-id-ruby", }, "libyaml": bias.Blob{ Name: "libyaml", Version: "fake-package-source-fingerprint-libyaml", SHA1: "fake-package-compiled-archive-sha1-libyaml", BlobstoreID: "fake-package-compiled-archive-blob-id-libyaml", }, }, RenderedTemplatesArchive: bias.RenderedTemplatesArchiveSpec{ BlobstoreID: "fake-rendered-job-list-archive-blob-id", SHA1: "fake-rendered-job-list-archive-sha1", }, ConfigurationHash: "fake-rendered-job-list-fingerprint", })) }) }) }