func validatePlan(c atc.Config, identifier string, plan atc.PlanConfig) []string { foundTypes := foundTypes{ identifier: identifier, found: make(map[string]bool), } if plan.Get != "" { foundTypes.Find("get") } if plan.Put != "" { foundTypes.Find("put") } if plan.Task != "" { foundTypes.Find("task") } if plan.Do != nil { foundTypes.Find("do") } if plan.Aggregate != nil { foundTypes.Find("aggregate") } if plan.Try != nil { foundTypes.Find("try") } if valid, message := foundTypes.IsValid(); !valid { return []string{message} } errorMessages := []string{} switch { case plan.Do != nil: for i, plan := range *plan.Do { subIdentifier := fmt.Sprintf("%s[%d]", identifier, i) errorMessages = append(errorMessages, validatePlan(c, subIdentifier, plan)...) } case plan.Aggregate != nil: for i, plan := range *plan.Aggregate { subIdentifier := fmt.Sprintf("%s.aggregate[%d]", identifier, i) errorMessages = append(errorMessages, validatePlan(c, subIdentifier, plan)...) } case plan.Get != "": subIdentifier := fmt.Sprintf("%s.get.%s", identifier, plan.Get) errorMessages = append(errorMessages, validateInapplicableFields( []string{"privileged", "config", "file"}, plan, subIdentifier)..., ) if plan.Resource != "" { _, found := c.Resources.Lookup(plan.Resource) if !found { errorMessages = append( errorMessages, fmt.Sprintf( "%s refers to a resource that does not exist ('%s')", subIdentifier, plan.Resource, ), ) } } else { _, found := c.Resources.Lookup(plan.Get) if !found { errorMessages = append( errorMessages, fmt.Sprintf( "%s refers to a resource that does not exist", subIdentifier, ), ) } } for _, job := range plan.Passed { jobConfig, found := c.Jobs.Lookup(job) if !found { errorMessages = append( errorMessages, fmt.Sprintf( "%s.passed references an unknown job ('%s')", subIdentifier, job, ), ) } else { foundResource := false for _, jobInput := range JobInputs(jobConfig) { if jobInput.Resource == plan.ResourceName() { foundResource = true break } } for _, jobOutput := range JobOutputs(jobConfig) { if jobOutput.Resource == plan.ResourceName() { foundResource = true break } } if !foundResource { errorMessages = append( errorMessages, fmt.Sprintf( "%s.passed references a job ('%s') which doesn't interact with the resource ('%s')", subIdentifier, job, plan.Get, ), ) } } } case plan.Put != "": subIdentifier := fmt.Sprintf("%s.put.%s", identifier, plan.Put) errorMessages = append(errorMessages, validateInapplicableFields( []string{"passed", "trigger", "privileged", "config", "file"}, plan, subIdentifier)..., ) if plan.Resource != "" { _, found := c.Resources.Lookup(plan.Resource) if !found { errorMessages = append( errorMessages, fmt.Sprintf( "%s refers to a resource that does not exist ('%s')", subIdentifier, plan.Resource, ), ) } } else { _, found := c.Resources.Lookup(plan.Put) if !found { errorMessages = append( errorMessages, fmt.Sprintf( "%s refers to a resource that does not exist", subIdentifier, ), ) } } case plan.Task != "": subIdentifier := fmt.Sprintf("%s.task.%s", identifier, plan.Task) if plan.TaskConfig == nil && plan.TaskConfigPath == "" { errorMessages = append(errorMessages, subIdentifier+" does not specify any task configuration") } errorMessages = append(errorMessages, validateInapplicableFields( []string{"resource", "passed", "trigger"}, plan, subIdentifier)..., ) if plan.Params != nil { errorMessages = append(errorMessages, subIdentifier+" specifies params, which should be config.params") } case plan.Try != nil: subIdentifier := fmt.Sprintf("%s.try", identifier) errorMessages = append(errorMessages, validatePlan(c, subIdentifier, *plan.Try)...) } if plan.Ensure != nil { subIdentifier := fmt.Sprintf("%s.ensure", identifier) errorMessages = append(errorMessages, validatePlan(c, subIdentifier, *plan.Ensure)...) } if plan.Success != nil { subIdentifier := fmt.Sprintf("%s.success", identifier) errorMessages = append(errorMessages, validatePlan(c, subIdentifier, *plan.Success)...) } if plan.Failure != nil { subIdentifier := fmt.Sprintf("%s.failure", identifier) errorMessages = append(errorMessages, validatePlan(c, subIdentifier, *plan.Failure)...) } if plan.Timeout != "" { _, err := time.ParseDuration(plan.Timeout) if err != nil { subIdentifier := fmt.Sprintf("%s.timeout", identifier) errorMessages = append(errorMessages, subIdentifier+fmt.Sprintf(" refers to a duration that could not be parsed ('%s')", plan.Timeout)) } } return errorMessages }