Beispiel #1
0
func describeMultilineError() {
	var err error

	It("returns a simple single-line message string (depth=0)", func() {
		err = bosherr.Error("omg")
		Expect(MultilineError(err)).To(Equal("omg"))
	})

	Context("when given a composite error", func() {
		It("returns a multi-line, indented message string (depth=1)", func() {
			err = bosherr.WrapError(bosherr.Error("inner omg"), "omg")
			Expect(MultilineError(err)).To(Equal("omg:\n  inner omg"))
		})

		It("returns a multi-line, indented message string (depth=2)", func() {
			err = bosherr.WrapError(bosherr.WrapError(bosherr.Error("inner omg"), "omg"), "outer omg")
			Expect(MultilineError(err)).To(Equal("outer omg:\n  omg:\n    inner omg"))
		})

		It("returns a multi-line, indented message string (depth=3)", func() {
			err = bosherr.WrapError(bosherr.WrapError(bosherr.WrapError(bosherr.Error("inner omg"), "almost inner omg"), "almost outer omg"), "outer omg")
			Expect(MultilineError(err)).To(Equal("outer omg:\n  almost outer omg:\n    almost inner omg:\n      inner omg"))
		})
	})

	Context("when given an explainable error", func() {
		It("returns a multi-line message string with sibling errors at the same indentation", func() {
			err = bosherr.NewMultiError(bosherr.Error("a"), bosherr.Error("b"))
			Expect(MultilineError(err)).To(Equal("a\nb"))
		})

		It("returns a multi-line message string with sibling errors at the same indentation", func() {
			complex := bosherr.WrapError(bosherr.Error("inner a"), "outer a")
			err = bosherr.NewMultiError(complex, bosherr.Error("b"))
			Expect(MultilineError(err)).To(Equal("outer a:\n  inner a\nb"))
		})

		It("returns a multi-line message string with sibling errors at the same indentation", func() {
			complex := bosherr.WrapError(bosherr.Error("inner b"), "outer b")
			err = bosherr.NewMultiError(bosherr.Error("a"), complex)
			Expect(MultilineError(err)).To(Equal("a\nouter b:\n  inner b"))
		})
	})

	Context("when given a composite err with explainable errors", func() {
		It("returns a multi-line message string with sibling errors at the same indentation", func() {
			multi := bosherr.NewMultiError(bosherr.Error("inner a"), bosherr.Error("inner b"))
			err = bosherr.WrapError(multi, "outer omg")
			Expect(MultilineError(err)).To(Equal("outer omg:\n  inner a\n  inner b"))
		})
	})

	Context("when given an ExecError", func() {
		It("returns a multi-line message string with the command, stdout, & stderr at the same indentation", func() {
			execErr := boshsys.NewExecError("fake-cmd --flag with some args", "some\nmultiline\nstdout", "some\nmultiline\nstderr")
			err = bosherr.WrapError(execErr, "outer omg")
			Expect(MultilineError(err)).To(Equal("outer omg:\n  Error Executing Command:\n    fake-cmd --flag with some args\n  StdOut:\n    some\n    multiline\n    stdout\n  StdErr:\n    some\n    multiline\n    stderr"))
		})
	})
}
Beispiel #2
0
func (v *validator) Validate(release Release) error {
	errs := []error{}

	err := v.validateReleaseName(release)
	if err != nil {
		errs = append(errs, bosherr.WrapError(err, "Validating release name"))
	}

	err = v.validateReleaseVersion(release)
	if err != nil {
		errs = append(errs, bosherr.WrapError(err, "Validating release version"))
	}

	err = v.validateReleaseJobs(release)
	if err != nil {
		errs = append(errs, bosherr.WrapError(err, "Validating release jobs"))
	}

	err = v.validateReleasePackages(release)
	if err != nil {
		errs = append(errs, bosherr.WrapError(err, "Validating release packages"))
	}

	if len(errs) > 0 {
		return bosherr.NewMultiError(errs...)
	}

	return nil
}
Beispiel #3
0
func (r *reader) newReleaseFromManifest(releaseManifest birelmanifest.Manifest) (Release, error) {
	errors := []error{}
	packages, isCompiledRelease, err := r.newPackagesFromManifestPackages(releaseManifest)
	if err != nil {
		errors = append(errors, bosherr.WrapError(err, "Constructing packages from manifest"))
	}

	jobs, err := r.newJobsFromManifestJobs(packages, releaseManifest.Jobs)
	if err != nil {
		errors = append(errors, bosherr.WrapError(err, "Constructing jobs from manifest"))
	}

	if len(errors) > 0 {
		return nil, bosherr.NewMultiError(errors...)
	}

	release := &release{
		name:    releaseManifest.Name,
		version: releaseManifest.Version,

		jobs:     jobs,
		packages: packages,

		extractedPath: r.extractedReleasePath,
		fs:            r.fs,
		isCompiled:    isCompiledRelease,
	}

	return release, nil
}
Beispiel #4
0
func (v *validator) validateReleaseJobs(release Release) error {
	errs := []error{}
	for _, job := range release.Jobs() {
		if job.Name == "" {
			errs = append(errs, errors.New("Job name is missing"))
		}

		if job.Fingerprint == "" {
			errs = append(errs, fmt.Errorf("Job '%s' fingerprint is missing", job.Name))
		}

		if job.SHA1 == "" {
			errs = append(errs, fmt.Errorf("Job '%s' sha1 is missing", job.Name))
		}

		monitPath := path.Join(job.ExtractedPath, "monit")
		if !v.fs.FileExists(monitPath) {
			errs = append(errs, fmt.Errorf("Job '%s' is missing monit file", job.Name))
		}

		for template := range job.Templates {
			templatePath := path.Join(job.ExtractedPath, "templates", template)
			if !v.fs.FileExists(templatePath) {
				errs = append(errs, fmt.Errorf("Job '%s' is missing template '%s'", job.Name, templatePath))
			}
		}

		for _, pkgName := range job.PackageNames {
			found := false
			for _, releasePackage := range release.Packages() {
				if releasePackage.Name == pkgName {
					found = true
					break
				}
			}
			if !found {
				errs = append(errs, fmt.Errorf("Job '%s' requires '%s' which is not in the release", job.Name, pkgName))
			}
		}
	}

	if len(errs) > 0 {
		return bosherr.NewMultiError(errs...)
	}

	return nil
}
Beispiel #5
0
func (v *validator) validateReleasePackages(release Release) error {
	errs := []error{}
	stemcells := map[string]string{}

	for _, pkg := range release.Packages() {
		if pkg.Name == "" {
			errs = append(errs, errors.New("Package name is missing"))
		}

		if pkg.Fingerprint == "" {
			errs = append(errs, fmt.Errorf("Package '%s' fingerprint is missing", pkg.Name))
		}

		if pkg.SHA1 == "" {
			errs = append(errs, fmt.Errorf("Package '%s' sha1 is missing", pkg.Name))
		}

		if release.IsCompiled() {
			if pkg.Stemcell == "" {
				errs = append(errs, fmt.Errorf("Compiled package '%s' stemcell is missing", pkg.Name))
			} else {
				stemcells[pkg.Stemcell] = pkg.Stemcell
			}
		}
	}

	if release.IsCompiled() && len(stemcells) > 1 {
		keys := []string{}
		for k := range stemcells {
			keys = append(keys, k)
		}
		sort.Strings(keys)
		errs = append(errs, fmt.Errorf("Packages were compiled against different stemcells: %v", keys))
	}

	if len(errs) > 0 {
		return bosherr.NewMultiError(errs...)
	}

	return nil
}
Beispiel #6
0
func (r *reader) newJobsFromManifestJobs(packages []*birelpkg.Package, manifestJobs []birelmanifest.JobRef) ([]bireljob.Job, error) {
	jobs := []bireljob.Job{}
	errors := []error{}
	for _, manifestJob := range manifestJobs {
		extractedJobPath := path.Join(r.extractedReleasePath, "extracted_jobs", manifestJob.Name)
		err := r.fs.MkdirAll(extractedJobPath, os.ModeDir|0700)
		if err != nil {
			errors = append(errors, bosherr.WrapError(err, "Creating extracted job path"))
			continue
		}

		jobArchivePath := path.Join(r.extractedReleasePath, "jobs", manifestJob.Name+".tgz")
		jobReader := bireljob.NewReader(jobArchivePath, extractedJobPath, r.extractor, r.fs)
		job, err := jobReader.Read()
		if err != nil {
			errors = append(errors, bosherr.WrapErrorf(err, "Reading job '%s' from archive", manifestJob.Name))
			continue
		}

		job.Fingerprint = manifestJob.Fingerprint
		job.SHA1 = manifestJob.SHA1
		for _, pkgName := range job.PackageNames {
			pkg, found := r.findPackageByName(packages, pkgName)
			if !found {
				return []bireljob.Job{}, bosherr.Errorf("Package not found: '%s'", pkgName)
			}
			job.Packages = append(job.Packages, pkg)
		}

		jobs = append(jobs, job)
	}

	if len(errors) > 0 {
		return []bireljob.Job{}, bosherr.NewMultiError(errors...)
	}

	return jobs, nil
}
Beispiel #7
0
func (v *validator) ValidateReleaseJobs(deploymentManifest Manifest, releaseManager birel.Manager) error {
	errs := []error{}

	for idx, job := range deploymentManifest.Jobs {
		for templateIdx, template := range job.Templates {
			release, found := releaseManager.Find(template.Release)
			if !found {
				errs = append(errs, bosherr.Errorf("jobs[%d].templates[%d].release '%s' must refer to release in releases", idx, templateIdx, template.Release))
			} else {
				_, found := release.FindJobByName(template.Name)
				if !found {
					errs = append(errs, bosherr.Errorf("jobs[%d].templates[%d] must refer to a job in '%s', but there is no job named '%s'", idx, templateIdx, release.Name(), template.Name))
				}
			}
		}
	}

	if len(errs) > 0 {
		return bosherr.NewMultiError(errs...)
	}

	return nil
}
Beispiel #8
0
func (v *validator) Validate(manifest Manifest) error {
	errs := []error{}
	releaseNames := map[string]struct{}{}
	if len(manifest.Releases) < 1 {
		errs = append(errs, bosherr.Errorf("releases must contain at least 1 release"))
	}

	for releaseIdx, release := range manifest.Releases {
		if v.isBlank(release.Name) {
			errs = append(errs, bosherr.Errorf("releases[%d].name must be provided", releaseIdx))
		}

		if _, found := releaseNames[release.Name]; found {
			errs = append(errs, bosherr.Errorf("releases[%d].name '%s' must be unique", releaseIdx, release.Name))
		}
		releaseNames[release.Name] = struct{}{}

		if v.isBlank(release.URL) {
			errs = append(errs, bosherr.Errorf("releases[%d].url must be provided", releaseIdx))
		}

		matched, err := regexp.MatchString("^(file|http|https)://", release.URL)
		if err != nil || !matched {
			errs = append(errs, bosherr.Errorf("releases[%d].url must be a valid URL (file:// or http(s)://)", releaseIdx))
		}

		if strings.HasPrefix(release.URL, "http") && v.isBlank(release.SHA1) {
			errs = append(errs, bosherr.Errorf("releases[%d].sha1 must be provided for http URL", releaseIdx))
		}
	}

	if len(errs) > 0 {
		return bosherr.NewMultiError(errs...)
	}

	return nil
}
Beispiel #9
0
func (v *validator) Validate(manifest Manifest, releaseSetManifest birelsetmanifest.Manifest) error {
	errs := []error{}

	cpiJobName := manifest.Template.Name
	if v.isBlank(cpiJobName) {
		errs = append(errs, bosherr.Error("cloud_provider.template.name must be provided"))
	}

	cpiReleaseName := manifest.Template.Release
	if v.isBlank(cpiReleaseName) {
		errs = append(errs, bosherr.Error("cloud_provider.template.release must be provided"))
	}

	_, found := releaseSetManifest.FindByName(cpiReleaseName)
	if !found {
		errs = append(errs, bosherr.Errorf("cloud_provider.template.release '%s' must refer to a release in releases", cpiReleaseName))
	}

	if len(errs) > 0 {
		return bosherr.NewMultiError(errs...)
	}

	return nil
}
Beispiel #10
0
func (r *reader) newPackagesFromManifestPackages(releaseManifest birelmanifest.Manifest) ([]*birelpkg.Package, bool, error) {

	manifestPackages := releaseManifest.Packages
	isCompiledPackage := false

	if len(releaseManifest.Packages) > 0 && len(releaseManifest.CompiledPackages) > 0 {
		return []*birelpkg.Package{}, isCompiledPackage, bosherr.Errorf("Release '%s' contains compiled and non-compiled pacakges", releaseManifest.Name)
	} else if len(releaseManifest.CompiledPackages) > 0 {
		manifestPackages = releaseManifest.CompiledPackages
		isCompiledPackage = true
	}

	packages := []*birelpkg.Package{}
	errors := []error{}
	packageRepo := &birelpkg.PackageRepo{}

	packagesDirectory := "packages"
	if isCompiledPackage {
		packagesDirectory = "compiled_packages"
	}

	for _, manifestPackage := range manifestPackages {
		pkg := packageRepo.FindOrCreatePackage(manifestPackage.Name)

		extractedPackagePath := path.Join(r.extractedReleasePath, "extracted_packages", manifestPackage.Name)
		err := r.fs.MkdirAll(extractedPackagePath, os.ModeDir|0700)
		if err != nil {
			errors = append(errors, bosherr.WrapError(err, "Creating extracted package path"))
			continue
		}

		packageArchivePath := path.Join(r.extractedReleasePath, packagesDirectory, manifestPackage.Name+".tgz")
		err = r.extractor.DecompressFileToDir(packageArchivePath, extractedPackagePath, boshcmd.CompressorOptions{})
		if err != nil {
			errors = append(errors, bosherr.WrapErrorf(err, "Extracting package '%s'", manifestPackage.Name))
			continue
		}

		pkg.Fingerprint = manifestPackage.Fingerprint
		pkg.SHA1 = manifestPackage.SHA1
		pkg.ExtractedPath = extractedPackagePath
		pkg.ArchivePath = packageArchivePath

		if isCompiledPackage {
			pkg.Stemcell = manifestPackage.Stemcell
		}

		pkg.Dependencies = []*birelpkg.Package{}
		for _, manifestPackageName := range manifestPackage.Dependencies {
			pkg.Dependencies = append(pkg.Dependencies, packageRepo.FindOrCreatePackage(manifestPackageName))
		}

		packages = append(packages, pkg)
	}

	if len(errors) > 0 {
		return []*birelpkg.Package{}, isCompiledPackage, bosherr.NewMultiError(errors...)
	}

	return packages, isCompiledPackage, nil
}
Beispiel #11
0
func (v *validator) Validate(deploymentManifest Manifest, releaseSetManifest birelsetmanifest.Manifest) error {
	errs := []error{}
	if v.isBlank(deploymentManifest.Name) {
		errs = append(errs, bosherr.Error("name must be provided"))
	}

	networksErrors := v.validateNetworks(deploymentManifest.Networks)
	errs = append(errs, networksErrors...)

	for idx, resourcePool := range deploymentManifest.ResourcePools {
		if v.isBlank(resourcePool.Name) {
			errs = append(errs, bosherr.Errorf("resource_pools[%d].name must be provided", idx))
		}
		if v.isBlank(resourcePool.Network) {
			errs = append(errs, bosherr.Errorf("resource_pools[%d].network must be provided", idx))
		} else if _, ok := v.networkNames(deploymentManifest)[resourcePool.Network]; !ok {
			errs = append(errs, bosherr.Errorf("resource_pools[%d].network must be the name of a network", idx))
		}

		if v.isBlank(resourcePool.Stemcell.URL) {
			errs = append(errs, bosherr.Errorf("resource_pools[%d].stemcell.url must be provided", idx))
		}

		matched, err := regexp.MatchString("^(file|http|https)://", resourcePool.Stemcell.URL)
		if err != nil || !matched {
			errs = append(errs, bosherr.Errorf("resource_pools[%d].stemcell.url must be a valid URL (file:// or http(s)://)", idx))
		}

		if strings.HasPrefix(resourcePool.Stemcell.URL, "http") && v.isBlank(resourcePool.Stemcell.SHA1) {
			errs = append(errs, bosherr.Errorf("resource_pools[%d].stemcell.sha1 must be provided for http URL", idx))
		}
	}

	for idx, diskPool := range deploymentManifest.DiskPools {
		if v.isBlank(diskPool.Name) {
			errs = append(errs, bosherr.Errorf("disk_pools[%d].name must be provided", idx))
		}
		if diskPool.DiskSize <= 0 {
			errs = append(errs, bosherr.Errorf("disk_pools[%d].disk_size must be > 0", idx))
		}
	}

	if len(deploymentManifest.Jobs) > 1 {
		errs = append(errs, bosherr.Error("jobs must be of size 1"))
	}

	for idx, job := range deploymentManifest.Jobs {
		if v.isBlank(job.Name) {
			errs = append(errs, bosherr.Errorf("jobs[%d].name must be provided", idx))
		}
		if job.PersistentDisk < 0 {
			errs = append(errs, bosherr.Errorf("jobs[%d].persistent_disk must be >= 0", idx))
		}
		if job.PersistentDiskPool != "" {
			if _, ok := v.diskPoolNames(deploymentManifest)[job.PersistentDiskPool]; !ok {
				errs = append(errs, bosherr.Errorf("jobs[%d].persistent_disk_pool must be the name of a disk pool", idx))
			}
		}
		if job.Instances < 0 {
			errs = append(errs, bosherr.Errorf("jobs[%d].instances must be >= 0", idx))
		}
		if len(job.Networks) == 0 {
			errs = append(errs, bosherr.Errorf("jobs[%d].networks must be a non-empty array", idx))
		}
		if v.isBlank(job.ResourcePool) {
			errs = append(errs, bosherr.Errorf("jobs[%d].resource_pool must be provided", idx))
		} else {
			if _, ok := v.resourcePoolNames(deploymentManifest)[job.ResourcePool]; !ok {
				errs = append(errs, bosherr.Errorf("jobs[%d].resource_pool must be the name of a resource pool", idx))
			}
		}

		errs = append(errs, v.validateJobNetworks(job.Networks, deploymentManifest.Networks, idx)...)

		if job.Lifecycle != "" && job.Lifecycle != JobLifecycleService {
			errs = append(errs, bosherr.Errorf("jobs[%d].lifecycle must be 'service' ('%s' not supported)", idx, job.Lifecycle))
		}

		templateNames := map[string]struct{}{}
		for templateIdx, template := range job.Templates {
			if v.isBlank(template.Name) {
				errs = append(errs, bosherr.Errorf("jobs[%d].templates[%d].name must be provided", idx, templateIdx))
			}
			if _, found := templateNames[template.Name]; found {
				errs = append(errs, bosherr.Errorf("jobs[%d].templates[%d].name '%s' must be unique", idx, templateIdx, template.Name))
			}
			templateNames[template.Name] = struct{}{}

			if v.isBlank(template.Release) {
				errs = append(errs, bosherr.Errorf("jobs[%d].templates[%d].release must be provided", idx, templateIdx))
			} else {
				_, found := releaseSetManifest.FindByName(template.Release)
				if !found {
					errs = append(errs, bosherr.Errorf("jobs[%d].templates[%d].release '%s' must refer to release in releases", idx, templateIdx, template.Release))
				}
			}
		}
	}

	if len(errs) > 0 {
		return bosherr.NewMultiError(errs...)
	}

	return nil
}