func finalizeWorkflows()

in testworkflow.go [596:721]


func finalizeWorkflows(ctx context.Context, tests []*TestWorkflow, zone, gcsPrefix, localPath string) error {
	log.Printf("Storing artifacts and logs in %s", gcsPrefix)
	for _, twf := range tests {
		if twf.wf == nil {
			return fmt.Errorf("found nil workflow in finalize")
		}

		twf.wf.StorageClient = client

		// $GCS_PATH/2021-04-20T11:44:08-07:00/image_validation/debian-10
		twf.GCSPath = fmt.Sprintf("%s/%s/%s", gcsPrefix, twf.Name, twf.Image.Name)
		twf.wf.GCSPath = twf.GCSPath

		twf.wf.Zone = zone

		// Process quota steps and associated creation steps.
		for quotaStepName, createStepName := range map[string]string{
			waitForVMQuotaStepName:    createVMsStepName,
			waitForDisksQuotaStepName: createDisksStepName,
		} {
			quotaStep, ok := twf.wf.Steps[quotaStepName]
			if !ok {
				continue
			}
			for _, q := range quotaStep.WaitForAvailableQuotas.Quotas {
				// Populate empty regions with best guess from the zone
				if q.Region == "" {
					lastIndex := strings.LastIndex(twf.wf.Zone, "-")
					q.Region = twf.wf.Zone[:lastIndex]
				}
			}
			createStep, ok := twf.wf.Steps[createStepName]
			if !ok {
				continue
			}
			// Fix dependencies. Create steps should depend on the quota step, and quota steps should inherit all other dependencies.
			for _, dep := range twf.wf.Dependencies[createStepName] {
				dStep, ok := twf.wf.Steps[dep]
				if ok {
					if err := twf.wf.AddDependency(quotaStep, dStep); err != nil {
						return err
					}
				}
			}
			if err := twf.wf.AddDependency(createStep, quotaStep); err != nil {
				return err
			}
		}

		// Assume amd64 when arch is not set.
		arch := "amd64"
		if twf.Image.Architecture == "ARM64" {
			arch = "arm64"
		}

		createDisksStep, createDisksOk := twf.wf.Steps[createDisksStepName]
		createVMsStep, ok := twf.wf.Steps[createVMsStepName]
		if ok {
			for _, vm := range createVMsStep.CreateInstances.Instances {
				if vm.MachineType != "" {
					log.Printf("VM %s machine type set to %s for test %s\n", vm.Name, vm.MachineType, twf.Name)
				} else {
					vm.MachineType = twf.MachineType.Name
				}
				if vm.Zone != "" && vm.Zone != twf.wf.Zone {
					log.Printf("VM %s zone is set to %s, differing from workflow zone %s for test %s, not overriding\n", vm.Name, vm.Zone, twf.wf.Zone, twf.Name)
				}
				if createDisksOk && (strings.HasPrefix(vm.MachineType, "c4-") || strings.HasPrefix(vm.MachineType, "n4-") || strings.HasPrefix(vm.MachineType, "c3-")) {
					for _, attachedDisk := range vm.Disks {
						for _, disk := range *createDisksStep.CreateDisks {
							if attachedDisk.Source == disk.Name && disk.Type == "" {
								disk.Type = HyperdiskBalanced
							}
						}
					}
				}

				// Correct initialize params disk types for custom attached disks.
				for _, attachedDisk := range vm.Disks {
					if attachedDisk.InitializeParams != nil {
						// Default to standard if no disk type is specified.
						if attachedDisk.InitializeParams.DiskType != "" && !strings.HasPrefix(attachedDisk.InitializeParams.DiskType, "zones/") {
							// Qualify the disk type with the zone if it's missing.
							attachedDisk.InitializeParams.DiskType = fmt.Sprintf("zones/%s/diskTypes/%s", vm.Zone, attachedDisk.InitializeParams.DiskType)
						}
					}
				}
			}
		}

		if utils.HasFeature(twf.Image, "WINDOWS") {
			archBits := "64"
			if strings.Contains(twf.ImageURL, "x86") {
				archBits = "32"
			}
			twf.wf.Sources["testpackage"] = fmt.Sprintf("%s/%s%s.exe", localPath, twf.Name, archBits)
			twf.wf.Sources["wrapper.exe"] = fmt.Sprintf("%s/%s%s.exe", localPath, testWrapperPathWindows, archBits)
		} else {
			twf.wf.Sources["testpackage"] = fmt.Sprintf("%s/%s.%s.test", localPath, twf.Name, arch)
			twf.wf.Sources["wrapper"] = fmt.Sprintf("%s%s.%s", localPath, testWrapperPath, arch)
		}

		// add a final copy-objects step which copies the daisy-outs-path directory to twf.gcsPath + /outs
		copyGCSObject := daisy.CopyGCSObject{}
		copyGCSObject.Source = "${OUTSPATH}/" // Trailing slash apparently crucial.
		copyGCSObject.Destination = twf.GCSPath + "/outs"
		copyGCSObjects := &daisy.CopyGCSObjects{copyGCSObject}
		copyStep, err := twf.wf.NewStep("copy-objects")
		if err != nil {
			return fmt.Errorf("failed to add copy-objects step to workflow %s: %v", twf.Name, err)
		}
		copyStep.CopyGCSObjects = copyGCSObjects

		// The "copy-objects" step depends on every wait step.
		for stepname, step := range twf.wf.Steps {
			if !strings.HasPrefix(stepname, "wait-") {
				continue
			}
			if err := twf.wf.AddDependency(copyStep, step); err != nil {
				return fmt.Errorf("failed to add copy-objects step: %v", err)
			}
		}

	}
	return nil
}