package opts import ( "sort" "strings" ) const ( // AllCapabilities is a special value to add or drop all capabilities AllCapabilities = "ALL" // ResetCapabilities is a special value to reset capabilities when updating. // This value should only be used when updating, not used on "create". ResetCapabilities = "RESET" ) // NormalizeCapability normalizes a capability by upper-casing, trimming white space // and adding a CAP_ prefix (if not yet present). This function also accepts the // "ALL" magic-value, as used by CapAdd/CapDrop. // // This function only handles rudimentary formatting; no validation is performed, // as the list of available capabilities can be updated over time, thus should be // handled by the daemon. func NormalizeCapability(cap string) string { cap = strings.ToUpper(strings.TrimSpace(cap)) if cap == AllCapabilities || cap == ResetCapabilities { return cap } if !strings.HasPrefix(cap, "CAP_") { cap = "CAP_" + cap } return cap } // CapabilitiesMap normalizes the given capabilities and converts them to a map. func CapabilitiesMap(caps []string) map[string]bool { normalized := make(map[string]bool) for _, c := range caps { normalized[NormalizeCapability(c)] = true } return normalized } // EffectiveCapAddCapDrop normalizes and sorts capabilities to "add" and "drop", // and returns the effective capabilities to include in both. // // "CapAdd" takes precedence over "CapDrop", so capabilities included in both // lists are removed from the list of capabilities to drop. The special "ALL" // capability is also taken into account. // // Note that the special "RESET" value is only used when updating an existing // service, and will be ignored. // // Duplicates are removed, and the resulting lists are sorted. func EffectiveCapAddCapDrop(add, drop []string) (capAdd, capDrop []string) { var ( addCaps = CapabilitiesMap(add) dropCaps = CapabilitiesMap(drop) ) if addCaps[AllCapabilities] { // Special case: "ALL capabilities" trumps any other capability added. addCaps = map[string]bool{AllCapabilities: true} } if dropCaps[AllCapabilities] { // Special case: "ALL capabilities" trumps any other capability added. dropCaps = map[string]bool{AllCapabilities: true} } for c := range dropCaps { if addCaps[c] { // Adding a capability takes precedence, so skip dropping continue } if c != ResetCapabilities { capDrop = append(capDrop, c) } } for c := range addCaps { if c != ResetCapabilities { capAdd = append(capAdd, c) } } sort.Strings(capAdd) sort.Strings(capDrop) return capAdd, capDrop }