// tasksUpdated does a diff between task groups to see if the // tasks, their drivers or config have updated. func tasksUpdated(a, b *structs.TaskGroup) bool { // If the number of tasks do not match, clearly there is an update if len(a.Tasks) != len(b.Tasks) { return true } // Check each task for _, at := range a.Tasks { bt := b.LookupTask(at.Name) if bt == nil { return true } if at.Driver != bt.Driver { return true } if !reflect.DeepEqual(at.Config, bt.Config) { return true } // Inspect the network to see if the dynamic ports are different if len(at.Resources.Networks) != len(bt.Resources.Networks) { return true } for idx := range at.Resources.Networks { an := at.Resources.Networks[idx] bn := bt.Resources.Networks[idx] if len(an.DynamicPorts) != len(bn.DynamicPorts) { return true } } } return false }
func parseGroups(result *structs.Job, list *ast.ObjectList) error { list = list.Children() if len(list.Items) == 0 { return nil } // Go through each object and turn it into an actual result. collection := make([]*structs.TaskGroup, 0, len(list.Items)) seen := make(map[string]struct{}) for _, item := range list.Items { n := item.Keys[0].Token.Value().(string) // Make sure we haven't already found this if _, ok := seen[n]; ok { return fmt.Errorf("group '%s' defined more than once", n) } seen[n] = struct{}{} // We need this later var listVal *ast.ObjectList if ot, ok := item.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return fmt.Errorf("group '%s': should be an object", n) } // Check for invalid keys valid := []string{ "count", "constraint", "restart", "meta", "task", "local_disk", } if err := checkHCLKeys(listVal, valid); err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s' ->", n)) } var m map[string]interface{} if err := hcl.DecodeObject(&m, item.Val); err != nil { return err } delete(m, "constraint") delete(m, "meta") delete(m, "task") delete(m, "restart") delete(m, "local_disk") // Default count to 1 if not specified if _, ok := m["count"]; !ok { m["count"] = 1 } // Build the group with the basic decode var g structs.TaskGroup g.Name = n if err := mapstructure.WeakDecode(m, &g); err != nil { return err } // Parse constraints if o := listVal.Filter("constraint"); len(o.Items) > 0 { if err := parseConstraints(&g.Constraints, o); err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s', constraint ->", n)) } } // Parse restart policy if o := listVal.Filter("restart"); len(o.Items) > 0 { if err := parseRestartPolicy(&g.RestartPolicy, o); err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s', restart ->", n)) } } // Parse local disk g.LocalDisk = structs.DefaultLocalDisk() if o := listVal.Filter("local_disk"); len(o.Items) > 0 { if err := parseLocalDisk(&g.LocalDisk, o); err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s', local_disk ->", n)) } } // Parse out meta fields. These are in HCL as a list so we need // to iterate over them and merge them. if metaO := listVal.Filter("meta"); len(metaO.Items) > 0 { for _, o := range metaO.Elem().Items { var m map[string]interface{} if err := hcl.DecodeObject(&m, o.Val); err != nil { return err } if err := mapstructure.WeakDecode(m, &g.Meta); err != nil { return err } } } // Parse tasks if o := listVal.Filter("task"); len(o.Items) > 0 { if err := parseTasks(result.Name, g.Name, &g.Tasks, o); err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s', task:", n)) } } collection = append(collection, &g) } result.TaskGroups = append(result.TaskGroups, collection...) return nil }
func parseGroups(result *structs.Job, obj *hclobj.Object) error { // Get all the maps of keys to the actual object objects := make(map[string]*hclobj.Object) for _, o1 := range obj.Elem(false) { for _, o2 := range o1.Elem(true) { if _, ok := objects[o2.Key]; ok { return fmt.Errorf( "group '%s' defined more than once", o2.Key) } objects[o2.Key] = o2 } } if len(objects) == 0 { return nil } // Go through each object and turn it into an actual result. collection := make([]*structs.TaskGroup, 0, len(objects)) for n, o := range objects { var m map[string]interface{} if err := hcl.DecodeObject(&m, o); err != nil { return err } delete(m, "constraint") delete(m, "meta") delete(m, "task") // Default count to 1 if not specified if _, ok := m["count"]; !ok { m["count"] = 1 } // Build the group with the basic decode var g structs.TaskGroup g.Name = n if err := mapstructure.WeakDecode(m, &g); err != nil { return err } // Parse constraints if o := o.Get("constraint", false); o != nil { if err := parseConstraints(&g.Constraints, o); err != nil { return err } } // Parse out meta fields. These are in HCL as a list so we need // to iterate over them and merge them. if metaO := o.Get("meta", false); metaO != nil { for _, o := range metaO.Elem(false) { var m map[string]interface{} if err := hcl.DecodeObject(&m, o); err != nil { return err } if err := mapstructure.WeakDecode(m, &g.Meta); err != nil { return err } } } // Parse tasks if o := o.Get("task", false); o != nil { if err := parseTasks(&g.Tasks, o); err != nil { return err } } collection = append(collection, &g) } result.TaskGroups = append(result.TaskGroups, collection...) return nil }
// tasksUpdated does a diff between task groups to see if the // tasks, their drivers, environment variables or config have updated. func tasksUpdated(a, b *structs.TaskGroup) bool { // If the number of tasks do not match, clearly there is an update if len(a.Tasks) != len(b.Tasks) { return true } // Check each task for _, at := range a.Tasks { bt := b.LookupTask(at.Name) if bt == nil { return true } if at.Driver != bt.Driver { return true } if at.User != bt.User { return true } if !reflect.DeepEqual(at.Config, bt.Config) { return true } if !reflect.DeepEqual(at.Env, bt.Env) { return true } if !reflect.DeepEqual(at.Meta, bt.Meta) { return true } if !reflect.DeepEqual(at.Artifacts, bt.Artifacts) { return true } // Inspect the network to see if the dynamic ports are different if len(at.Resources.Networks) != len(bt.Resources.Networks) { return true } for idx := range at.Resources.Networks { an := at.Resources.Networks[idx] bn := bt.Resources.Networks[idx] if an.MBits != bn.MBits { return true } aPorts, bPorts := networkPortMap(an), networkPortMap(bn) if !reflect.DeepEqual(aPorts, bPorts) { return true } } // Inspect the non-network resources if ar, br := at.Resources, bt.Resources; ar.CPU != br.CPU { return true } else if ar.MemoryMB != br.MemoryMB { return true } else if ar.DiskMB != br.DiskMB { return true } else if ar.IOPS != br.IOPS { return true } } return false }