func (d Manifest) DiskPool(jobName string) (DiskPool, error) { job, found := d.FindJobByName(jobName) if !found { return DiskPool{}, bosherr.Errorf("Could not find job with name: %s", jobName) } if job.PersistentDiskPool != "" { for _, diskPool := range d.DiskPools { if diskPool.Name == job.PersistentDiskPool { return diskPool, nil } } err := bosherr.Errorf("Could not find persistent disk pool '%s' for job '%s'", job.PersistentDiskPool, jobName) return DiskPool{}, err } if job.PersistentDisk > 0 { diskPool := DiskPool{ DiskSize: job.PersistentDisk, CloudProperties: biproperty.Map{}, } return diskPool, nil } return DiskPool{}, nil }
func (d *deployer) createAllInstances( deploymentManifest bideplmanifest.Manifest, instanceManager biinstance.Manager, cloudStemcell bistemcell.CloudStemcell, registryConfig biinstallmanifest.Registry, deployStage biui.Stage, ) ([]biinstance.Instance, []bidisk.Disk, error) { instances := []biinstance.Instance{} disks := []bidisk.Disk{} if len(deploymentManifest.Jobs) != 1 { return instances, disks, bosherr.Errorf("There must only be one job, found %d", len(deploymentManifest.Jobs)) } for _, jobSpec := range deploymentManifest.Jobs { if jobSpec.Instances != 1 { return instances, disks, bosherr.Errorf("Job '%s' must have only one instance, found %d", jobSpec.Name, jobSpec.Instances) } for instanceID := 0; instanceID < jobSpec.Instances; instanceID++ { instance, instanceDisks, err := instanceManager.Create(jobSpec.Name, instanceID, deploymentManifest, cloudStemcell, registryConfig, deployStage) if err != nil { return instances, disks, bosherr.WrapErrorf(err, "Creating instance '%s/%d'", jobSpec.Name, instanceID) } instances = append(instances, instance) disks = append(disks, instanceDisks...) err = instance.UpdateJobs(deploymentManifest, deployStage) if err != nil { return instances, disks, err } } } return instances, disks, nil }
// Build creates a generic property that may be a Map, List or primitive. // If it is a Map or List it will be built using the appropriate builder and constraints. func Build(val interface{}) (Property, error) { if val == nil { return nil, nil } switch reflect.TypeOf(val).Kind() { case reflect.Map: valMap, ok := val.(map[interface{}]interface{}) if !ok { return nil, bosherr.Errorf("Converting map %#v", val) } return BuildMap(valMap) case reflect.Slice: valSlice, ok := val.([]interface{}) if !ok { return nil, bosherr.Errorf("Converting slice %#v", val) } return BuildList(valSlice) default: return val, nil } }
func (v *validator) validateGateway(idx int, gateway string, ipNet maybeIPNet) []error { if v.isBlank(gateway) { return []error{bosherr.Errorf("networks[%d].subnets[0].gateway must be provided", idx)} } else { errors := []error{} ipNet.Try(func(ipNet *net.IPNet) error { gatewayIp := net.ParseIP(gateway) if gatewayIp == nil { errors = append(errors, bosherr.Errorf("networks[%d].subnets[0].gateway must be an ip", idx)) } if !ipNet.Contains(gatewayIp) { errors = append(errors, bosherr.Errorf("subnet gateway '%s' must be within the specified range '%s'", gateway, ipNet)) } if ipNet.IP.Equal(gatewayIp) { errors = append(errors, bosherr.Errorf("subnet gateway can't be the network address '%s'", gatewayIp)) } if binet.LastAddress(ipNet).Equal(gatewayIp) { errors = append(errors, bosherr.Errorf("subnet gateway can't be the broadcast address '%s'", gatewayIp)) } return nil }) return errors } }
func (v *validator) validateNetwork(network Network, networkIdx int) []error { errs := []error{} if v.isBlank(network.Name) { errs = append(errs, bosherr.Errorf("networks[%d].name must be provided", networkIdx)) } if network.Type != Dynamic && network.Type != Manual && network.Type != VIP { errs = append(errs, bosherr.Errorf("networks[%d].type must be 'manual', 'dynamic', or 'vip'", networkIdx)) } if network.Type == Manual { if len(network.Subnets) != 1 { errs = append(errs, bosherr.Errorf("networks[%d].subnets must be of size 1", networkIdx)) } else { ipRange := network.Subnets[0].Range rangeErrors, maybeIpNet := v.validateRange(networkIdx, ipRange) errs = append(errs, rangeErrors...) gateway := network.Subnets[0].Gateway gatewayErrors := v.validateGateway(networkIdx, gateway, maybeIpNet) errs = append(errs, gatewayErrors...) } } return errs }
func (r ipResolver) GetPrimaryIPv4(interfaceName string) (*gonet.IPNet, error) { addrs, err := r.ifaceToAddrsFunc(interfaceName) if err != nil { return nil, bosherr.WrapErrorf(err, "Looking up addresses for interface '%s'", interfaceName) } if len(addrs) == 0 { return nil, bosherr.Errorf("No addresses found for interface '%s'", interfaceName) } for _, addr := range addrs { ip, ok := addr.(*gonet.IPNet) if !ok { continue } // ignore ipv6 if ip.IP.To4() == nil { continue } return ip, nil } return nil, bosherr.Errorf("Failed to find primary IPv4 address for interface '%s'", interfaceName) }
func (p rootDevicePartitioner) Partition(devicePath string, partitions []Partition) error { existingPartitions, deviceFullSizeInBytes, err := p.getPartitions(devicePath) if err != nil { return bosherr.WrapErrorf(err, "Getting existing partitions of `%s'", devicePath) } p.logger.Debug(p.logTag, "Current partitions: %#v", existingPartitions) if len(existingPartitions) == 0 { return bosherr.Errorf("Missing first partition on `%s'", devicePath) } if p.partitionsMatch(existingPartitions[1:], partitions) { p.logger.Info(p.logTag, "Partitions already match, skipping partitioning") return nil } if len(existingPartitions) > 1 { p.logger.Error(p.logTag, "Failed to create ephemeral partitions on root device `%s'. Expected 1 partition, found %d: %s", devicePath, len(existingPartitions), existingPartitions, ) return bosherr.Errorf("Found %d unexpected partitions on `%s'", len(existingPartitions)-1, devicePath) } // To support optimal reads on HDDs and optimal erasure on SSD: use 1MiB partition alignments. alignmentInBytes := uint64(1048576) partitionStart := p.roundUp(existingPartitions[0].EndInBytes+1, alignmentInBytes) for index, partition := range partitions { partitionEnd := partitionStart + partition.SizeInBytes - 1 if partitionEnd >= deviceFullSizeInBytes { partitionEnd = deviceFullSizeInBytes - 1 p.logger.Info(p.logTag, "Partition %d would be larger than remaining space. Reducing size to %dB", index, partitionEnd-partitionStart) } p.logger.Info(p.logTag, "Creating partition %d with start %dB and end %dB", index, partitionStart, partitionEnd) _, _, _, err := p.cmdRunner.RunCommand( "parted", "-s", devicePath, "unit", "B", "mkpart", "primary", fmt.Sprintf("%d", partitionStart), fmt.Sprintf("%d", partitionEnd), ) if err != nil { return bosherr.WrapErrorf(err, "Partitioning disk `%s'", devicePath) } partitionStart = p.roundUp(partitionEnd+1, alignmentInBytes) } return nil }
func NewWatchTime(timeRange string) (WatchTime, error) { parts := strings.Split(timeRange, "-") if len(parts) != 2 { return WatchTime{}, bosherr.Errorf("Invalid watch time range '%s'", timeRange) } start, err := strconv.Atoi(strings.Trim(parts[0], " ")) if err != nil { return WatchTime{}, bosherr.WrapErrorf( err, "Non-positive number as watch time minimum %s", parts[0]) } end, err := strconv.Atoi(strings.Trim(parts[1], " ")) if err != nil { return WatchTime{}, bosherr.WrapErrorf( err, "Non-positive number as watch time maximum %s", parts[1]) } if end < start { return WatchTime{}, bosherr.Errorf( "Watch time must have maximum greater than or equal minimum %s", timeRange) } return WatchTime{ Start: start, End: end, }, nil }
func (v *validator) validateJobNetworks(jobNetworks []JobNetwork, networks []Network, jobIdx int) []error { errs := []error{} defaultCounts := make(map[NetworkDefault]int) for networkIdx, jobNetwork := range jobNetworks { if v.isBlank(jobNetwork.Name) { errs = append(errs, bosherr.Errorf("jobs[%d].networks[%d].name must be provided", jobIdx, networkIdx)) } var matchingNetwork Network found := false for _, network := range networks { if network.Name == jobNetwork.Name { found = true matchingNetwork = network } } if !found { errs = append(errs, bosherr.Errorf("jobs[%d].networks[%d] not found in networks", jobIdx, networkIdx)) } for ipIdx, ip := range jobNetwork.StaticIPs { staticIPErrors := v.validateStaticIP(ip, jobNetwork, matchingNetwork, jobIdx, networkIdx, ipIdx) errs = append(errs, staticIPErrors...) } for defaultIdx, value := range jobNetwork.Defaults { if value != NetworkDefaultDNS && value != NetworkDefaultGateway { errs = append(errs, bosherr.Errorf("jobs[%d].networks[%d].default[%d] must be 'dns' or 'gateway'", jobIdx, networkIdx, defaultIdx)) } } for _, dflt := range jobNetwork.Defaults { count, present := defaultCounts[dflt] if present { defaultCounts[dflt] = count + 1 } else { defaultCounts[dflt] = 1 } } } for _, dflt := range []NetworkDefault{"dns", "gateway"} { count, found := defaultCounts[dflt] if len(jobNetworks) > 1 && !found { errs = append(errs, bosherr.Errorf("with multiple networks, a default for '%s' must be specified", dflt)) } else if count > 1 { errs = append(errs, bosherr.Errorf("only one network can be the default for '%s'", dflt)) } } return errs }
func (v *validator) validateRange(idx int, ipRange string) ([]error, maybeIPNet) { if v.isBlank(ipRange) { return []error{bosherr.Errorf("networks[%d].subnets[0].range must be provided", idx)}, ¬hingIpNet{} } else { _, ipNet, err := net.ParseCIDR(ipRange) if err != nil { return []error{bosherr.Errorf("networks[%d].subnets[0].range must be an ip range", idx)}, ¬hingIpNet{} } return []error{}, &somethingIpNet{ipNet: ipNet} } }
func (v Validator) Validate(release birel.Release, cpiReleaseJobName string) error { job, ok := release.FindJobByName(cpiReleaseJobName) if !ok { return bosherr.Errorf("CPI release must contain specified job '%s'", cpiReleaseJobName) } _, ok = job.FindTemplateByValue(ReleaseBinaryName) if !ok { return bosherr.Errorf("Specified CPI release job '%s' must contain a template that renders to target '%s'", cpiReleaseJobName, ReleaseBinaryName) } return nil }
func (r *TaskResponse) TaskID() (string, error) { complexResponse, ok := r.Value.(map[string]interface{}) if !ok { return "", bosherr.Errorf("Failed to convert agent response to map %#v\n%s", r.Value, debug.Stack()) } agentTaskID, ok := complexResponse["agent_task_id"] if !ok { return "", bosherr.Errorf("Failed to parse task id from agent response %#v", r.Value) } return agentTaskID.(string), nil }
func (r *resolver) Resolve(jobName, releaseName string) (bireljob.Job, error) { release, found := r.releaseManager.Find(releaseName) if !found { return bireljob.Job{}, bosherr.Errorf("Finding release '%s'", releaseName) } releaseJob, found := release.FindJobByName(jobName) if !found { return bireljob.Job{}, bosherr.Errorf("Finding job '%s' in release '%s'", jobName, releaseName) } return releaseJob, nil }
func (d Manifest) ResourcePool(jobName string) (ResourcePool, error) { job, found := d.FindJobByName(jobName) if !found { return ResourcePool{}, bosherr.Errorf("Could not find job with name: %s", jobName) } for _, resourcePool := range d.ResourcePools { if resourcePool.Name == job.ResourcePool { return resourcePool, nil } } err := bosherr.Errorf("Could not find resource pool '%s' for job '%s'", job.ResourcePool, jobName) return ResourcePool{}, err }
func (c *agentClient) CompilePackage(packageSource agentclient.BlobRef, compiledPackageDependencies []agentclient.BlobRef) (compiledPackageRef agentclient.BlobRef, err error) { dependencies := make(map[string]BlobRef, len(compiledPackageDependencies)) for _, dependency := range compiledPackageDependencies { dependencies[dependency.Name] = BlobRef{ Name: dependency.Name, Version: dependency.Version, SHA1: dependency.SHA1, BlobstoreID: dependency.BlobstoreID, } } args := []interface{}{ packageSource.BlobstoreID, packageSource.SHA1, packageSource.Name, packageSource.Version, dependencies, } responseValue, err := c.sendAsyncTaskMessage("compile_package", args) if err != nil { return agentclient.BlobRef{}, bosherr.WrapError(err, "Sending 'compile_package' to the agent") } result, ok := responseValue["result"].(map[string]interface{}) if !ok { return agentclient.BlobRef{}, bosherr.Errorf("Unable to parse 'compile_package' response from the agent: %#v", responseValue) } sha1, ok := result["sha1"].(string) if !ok { return agentclient.BlobRef{}, bosherr.Errorf("Unable to parse 'compile_package' response from the agent: %#v", responseValue) } blobstoreID, ok := result["blobstore_id"].(string) if !ok { return agentclient.BlobRef{}, bosherr.Errorf("Unable to parse 'compile_package' response from the agent: %#v", responseValue) } compiledPackageRef = agentclient.BlobRef{ Name: packageSource.Name, Version: packageSource.Version, SHA1: sha1, BlobstoreID: blobstoreID, } return compiledPackageRef, nil }
func (b externalBlobstore) Validate() error { if !b.runner.CommandExists(b.executable()) { return bosherr.Errorf("executable %s not found in PATH", b.executable()) } return b.writeConfigFile() }
func (c cloud) CreateVM( agentID string, stemcellCID string, cloudProperties biproperty.Map, networksInterfaces map[string]biproperty.Map, env biproperty.Map, ) (string, error) { method := "create_vm" diskLocality := []interface{}{} // not used with bosh-init cmdOutput, err := c.cpiCmdRunner.Run( c.context, method, agentID, stemcellCID, cloudProperties, networksInterfaces, diskLocality, env, ) if err != nil { return "", err } if cmdOutput.Error != nil { return "", NewCPIError(method, *cmdOutput.Error) } // for create_vm, the result is a string of the vm cid cidString, ok := cmdOutput.Result.(string) if !ok { return "", bosherr.Errorf("Unexpected external CPI command result: '%#v'", cmdOutput.Result) } return cidString, nil }
func (cl CommandList) Create(name string) (Cmd, error) { if cl[name] == nil { return nil, bosherr.Errorf("Command '%s' unknown. See 'bosh-init help'", name) } return cl[name]() }
func (p provider) Get(name string) (Platform, error) { plat, found := p.platforms[name] if !found { return nil, bosherror.Errorf("Platform %s could not be found", name) } return plat, nil }
func (c cloud) CreateDisk(size int, cloudProperties biproperty.Map, vmCID string) (string, error) { c.logger.Debug(c.logTag, "Creating disk with size %d, cloudProperties %#v, instanceID %s", size, cloudProperties, vmCID, ) method := "create_disk" cmdOutput, err := c.cpiCmdRunner.Run( c.context, method, size, cloudProperties, vmCID, ) if err != nil { return "", err } if cmdOutput.Error != nil { return "", NewCPIError(method, *cmdOutput.Error) } cidString, ok := cmdOutput.Result.(string) if !ok { return "", bosherr.Errorf("Unexpected external CPI command result: '%#v'", cmdOutput.Result) } return cidString, nil }
func (r diskRepo) Save(cid string, size int, cloudProperties biproperty.Map) (DiskRecord, error) { config, records, err := r.load() if err != nil { return DiskRecord{}, err } oldRecord, found := r.find(records, cid) if found { return DiskRecord{}, bosherr.Errorf("Failed to save disk cid '%s', existing record found '%#v'", cid, oldRecord) } newRecord := DiskRecord{ CID: cid, Size: size, CloudProperties: cloudProperties, } newRecord.ID, err = r.uuidGenerator.Generate() if err != nil { return newRecord, bosherr.WrapError(err, "Generating disk id") } records = append(records, newRecord) config.Disks = records err = r.deploymentStateService.Save(config) if err != nil { return newRecord, bosherr.WrapError(err, "Saving new config") } return newRecord, nil }
// Upload stemcell to an IAAS. It does the following steps: // 1) uploads the stemcell to the cloud (if needed), // 2) saves a record of the uploaded stemcell in the repo func (m *manager) Upload(extractedStemcell ExtractedStemcell, uploadStage biui.Stage) (cloudStemcell CloudStemcell, err error) { manifest := extractedStemcell.Manifest() stageName := fmt.Sprintf("Uploading stemcell '%s/%s'", manifest.Name, manifest.Version) err = uploadStage.Perform(stageName, func() error { foundStemcellRecord, found, err := m.repo.Find(manifest.Name, manifest.Version) if err != nil { return bosherr.WrapError(err, "Finding existing stemcell record in repo") } if found { cloudStemcell = NewCloudStemcell(foundStemcellRecord, m.repo, m.cloud) return biui.NewSkipStageError(bosherr.Errorf("Found stemcell: %#v", foundStemcellRecord), "Stemcell already uploaded") } cid, err := m.cloud.CreateStemcell(manifest.ImagePath, manifest.CloudProperties) if err != nil { return bosherr.WrapErrorf(err, "creating stemcell (%s %s)", manifest.Name, manifest.Version) } stemcellRecord, err := m.repo.Save(manifest.Name, manifest.Version, cid) if err != nil { //TODO: delete stemcell from cloud when saving fails return bosherr.WrapErrorf(err, "saving stemcell record in repo (cid=%s, stemcell=%s)", cid, extractedStemcell) } cloudStemcell = NewCloudStemcell(stemcellRecord, m.repo, m.cloud) return nil }) if err != nil { return cloudStemcell, err } return cloudStemcell, nil }
func (c *deployCmd) Run(stage biui.Stage, args []string) error { deploymentManifestPath, err := c.parseCmdInputs(args) if err != nil { return err } manifestAbsFilePath, err := filepath.Abs(deploymentManifestPath) if err != nil { c.ui.ErrorLinef("Failed getting absolute path to deployment file '%s'", deploymentManifestPath) return bosherr.WrapErrorf(err, "Getting absolute path to deployment file '%s'", deploymentManifestPath) } if !c.fs.FileExists(manifestAbsFilePath) { c.ui.ErrorLinef("Deployment '%s' does not exist", manifestAbsFilePath) return bosherr.Errorf("Deployment manifest does not exist at '%s'", manifestAbsFilePath) } c.ui.PrintLinef("Deployment manifest: '%s'", manifestAbsFilePath) deploymentPreparer, err := c.deploymentPreparerProvider(manifestAbsFilePath) if err != nil { return err } return deploymentPreparer.PrepareDeployment(stage) }
func (p rootDevicePartitioner) GetDeviceSizeInBytes(devicePath string) (uint64, error) { p.logger.Debug(p.logTag, "Getting size of disk remaining after first partition") stdout, _, _, err := p.cmdRunner.RunCommand("parted", "-m", devicePath, "unit", "B", "print") if err != nil { return 0, bosherr.WrapErrorf(err, "Getting remaining size of `%s'", devicePath) } allLines := strings.Split(stdout, "\n") if len(allLines) < 3 { return 0, bosherr.Errorf("Getting remaining size of `%s'", devicePath) } partitionInfoLines := allLines[1:3] deviceInfo := strings.Split(partitionInfoLines[0], ":") deviceFullSizeInBytes, err := strconv.ParseUint(strings.TrimRight(deviceInfo[1], "B"), 10, 64) if err != nil { return 0, bosherr.WrapErrorf(err, "Getting remaining size of `%s'", devicePath) } firstPartitionInfo := strings.Split(partitionInfoLines[1], ":") firstPartitionEndInBytes, err := strconv.ParseUint(strings.TrimRight(firstPartitionInfo[2], "B"), 10, 64) if err != nil { return 0, bosherr.WrapErrorf(err, "Getting remaining size of `%s'", devicePath) } remainingSizeInBytes := deviceFullSizeInBytes - firstPartitionEndInBytes - 1 return remainingSizeInBytes, nil }
func (idpr idDevicePathResolver) GetRealDevicePath(diskSettings boshsettings.DiskSettings) (string, bool, error) { if diskSettings.ID == "" { return "", false, bosherr.Errorf("Disk ID is not set") } if len(diskSettings.ID) < 20 { return "", false, bosherr.Errorf("Disk ID is not the correct format") } err := idpr.udev.Trigger() if err != nil { return "", false, bosherr.WrapError(err, "Running udevadm trigger") } err = idpr.udev.Settle() if err != nil { return "", false, bosherr.WrapError(err, "Running udevadm settle") } stopAfter := time.Now().Add(idpr.diskWaitTimeout) found := false var realPath string diskID := diskSettings.ID[0:20] for !found { if time.Now().After(stopAfter) { return "", true, bosherr.Errorf("Timed out getting real device path for '%s'", diskID) } time.Sleep(100 * time.Millisecond) deviceIDPath := filepath.Join(string(os.PathSeparator), "dev", "disk", "by-id", fmt.Sprintf("virtio-%s", diskID)) realPath, err = idpr.fs.ReadLink(deviceIDPath) if err != nil { continue } if idpr.fs.FileExists(realPath) { found = true } } return realPath, false, nil }
func (m *manager) DeleteAll() error { for _, release := range m.releases { deleteErr := release.Delete() if deleteErr != nil { return bosherr.Errorf("Failed to delete extracted release '%s': %s", release.Name(), deleteErr.Error()) } } m.releases = []Release{} return nil }
// FIXME: why do i exist here and in installation/state/builder.go?? func (b *builder) resolveJobs(jobRefs []bideplmanifest.ReleaseJobRef) ([]bireljob.Job, error) { releaseJobs := make([]bireljob.Job, len(jobRefs), len(jobRefs)) for i, jobRef := range jobRefs { release, err := b.releaseJobResolver.Resolve(jobRef.Name, jobRef.Release) if err != nil { return releaseJobs, bosherr.Errorf("Resolving job '%s' in release '%s'", jobRef.Name, jobRef.Release) } releaseJobs[i] = release } return releaseJobs, nil }
func (v *FakeValidator) Validate(manifest birelsetmanifest.Manifest) error { v.ValidateInputs = append(v.ValidateInputs, ValidateInput{ Manifest: manifest, }) if len(v.validateOutputs) == 0 { return bosherr.Errorf("Unexpected FakeValidator.Validate(manifest) called with manifest: %#v", manifest) } validateOutput := v.validateOutputs[0] v.validateOutputs = v.validateOutputs[1:] return validateOutput.Err }
func (r *getStateRetryable) Attempt() (bool, error) { stateResponse, err := r.agentClient.GetState() if err != nil { return false, err } if stateResponse.JobState == "running" { return true, nil } return true, bosherr.Errorf("Received non-running job state: '%s'", stateResponse.JobState) }
func CreateStemcell(stemcellSrcDir string, stemcellPath string) error { session, err := RunCommand("tar", "-zcf", stemcellPath, "-C", stemcellSrcDir, ".") if err != nil { return err } if session.ExitCode() != 0 { return bosherr.Errorf("Failed to create stemcell src:'%s' dest:'%s'", stemcellSrcDir, stemcellPath) } return nil }