]> ruderich.org/simon Gitweb - safcm/safcm.git/blobdiff - cmd/safcm/config/groups.go
config: return map from TransitivelyDetectedGroups()
[safcm/safcm.git] / cmd / safcm / config / groups.go
index 7f7cb3f635c346663808e69e990aac020040b345..466e493c401ea895062294304b0961c5f360ce2d 100644 (file)
@@ -34,7 +34,7 @@ const (
        GroupRemoveSuffix     = GroupSpecialSeparator + "remove"
 )
 
-// Keep in sync with sync_info.go:infoGroupDetectedRegexp
+// Keep in sync with cmd/safcm/sync_info.go:infoGroupDetectedRegexp
 var groupNameRegexp = regexp.MustCompile(`^[a-z0-9_-]+$`)
 
 func LoadGroups(cfg *Config, hosts *Hosts) (map[string][]string, error) {
@@ -60,7 +60,9 @@ func LoadGroups(cfg *Config, hosts *Hosts) (map[string][]string, error) {
                                "%s conflict with pre-defined group %q",
                                errPrefix, name)
                }
-               if hosts.Map[name] != nil {
+               if hosts.Map[name] != nil ||
+                       hosts.Map[strings.TrimSuffix(name,
+                               GroupRemoveSuffix)] != nil {
                        return nil, fmt.Errorf(
                                "%s conflict with existing host",
                                errPrefix)
@@ -84,6 +86,8 @@ func LoadGroups(cfg *Config, hosts *Hosts) (map[string][]string, error) {
                        if x == GroupAll {
                                continue
                        }
+                       // Don't validate against groupNameRegexp because
+                       // hosts have less strict restrictions.
                        if strings.Contains(x, GroupSpecialSeparator) {
                                return nil, fmt.Errorf(
                                        "%s member %q must not contain %q",
@@ -95,14 +99,14 @@ func LoadGroups(cfg *Config, hosts *Hosts) (map[string][]string, error) {
                        if hosts.Map[x] != nil || groups[x] != nil {
                                continue
                        }
-                       return nil, fmt.Errorf("%s group %q not found",
+                       return nil, fmt.Errorf("%s member %q not found",
                                errPrefix, x)
                }
        }
 
        // Sanity check for global configuration
-       for _, x := range cfg.GroupOrder {
-               const errPrefix = "config.yaml: group_order:"
+       for _, x := range cfg.GroupPriority {
+               const errPrefix = "config.yaml: group_priority:"
 
                if x == GroupAll {
                        continue
@@ -124,11 +128,10 @@ func LoadGroups(cfg *Config, hosts *Hosts) (map[string][]string, error) {
        return groups, nil
 }
 
-func ResolveHostGroups(host string,
-       groups map[string][]string,
+func ResolveHostGroups(host string, groups map[string][]string,
        detectedGroups []string) ([]string, error) {
 
-       const maxDepth = 100
+       const maxRecursionDepth = 100
 
        detectedGroupsMap := make(map[string]bool)
        for _, x := range detectedGroups {
@@ -140,7 +143,7 @@ func ResolveHostGroups(host string,
        // groups).
        var lookup func(string, int) bool
        lookup = func(group string, depth int) bool {
-               if depth > maxDepth {
+               if depth > maxRecursionDepth {
                        cycle = &group
                        return false
                }
@@ -186,3 +189,36 @@ func ResolveHostGroups(host string,
        sort.Strings(res)
        return res, nil
 }
+
+// TransitivelyDetectedGroups returns all groups which depend on "detected"
+// groups, either directly or by depending on groups which transitively depend
+// on "detected" groups.
+func TransitivelyDetectedGroups(groups map[string][]string) map[string]bool {
+       work := make(map[string][]string)
+       for k, v := range groups {
+               work[k] = v
+       }
+
+       // Mark all groups which contain "detected" groups as long as new
+       // (transitive) "detected" groups are found.
+       detected := make(map[string]bool)
+       for {
+               change := false
+               for group, members := range work {
+                       for _, x := range members {
+                               if !detected[x] && !strings.HasPrefix(x,
+                                       GroupDetectedPrefix) {
+                                       continue
+                               }
+                               detected[strings.TrimSuffix(group,
+                                       GroupRemoveSuffix)] = true
+                               delete(work, group)
+                               change = true
+                       }
+               }
+               if !change {
+                       break
+               }
+       }
+       return detected
+}