github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/drivers/shared/capabilities/set.go (about)

     1  // Package capabilities is used for managing sets of linux capabilities.
     2  package capabilities
     3  
     4  import (
     5  	"sort"
     6  	"strings"
     7  )
     8  
     9  type nothing struct{}
    10  
    11  var null = nothing{}
    12  
    13  // Set represents a group linux capabilities, implementing some useful set
    14  // operations, taking care of name normalization, and sentinel value expansions.
    15  //
    16  // Linux capabilities can be expressed in multiple ways when working with docker
    17  // and/or executor, along with Nomad configuration.
    18  //
    19  // Capability names may be upper or lower case, and may or may not be prefixed
    20  // with "CAP_" or "cap_". On top of that, Nomad interprets the special name "all"
    21  // and "ALL" to mean "all capabilities supported by the operating system".
    22  type Set struct {
    23  	data map[string]nothing
    24  }
    25  
    26  // New creates a new Set setting caps as the initial elements.
    27  func New(caps []string) *Set {
    28  	m := make(map[string]nothing, len(caps))
    29  	for _, c := range caps {
    30  		insert(m, c)
    31  	}
    32  	return &Set{data: m}
    33  }
    34  
    35  // Add cap into s.
    36  func (s *Set) Add(cap string) {
    37  	insert(s.data, cap)
    38  }
    39  
    40  func insert(data map[string]nothing, cap string) {
    41  	switch name := normalize(cap); name {
    42  	case "":
    43  	case "all":
    44  		for k, v := range Supported().data {
    45  			data[k] = v
    46  		}
    47  		return
    48  	default:
    49  		data[name] = null
    50  	}
    51  }
    52  
    53  // Remove caps from s.
    54  func (s *Set) Remove(caps []string) {
    55  	for _, c := range caps {
    56  		name := normalize(c)
    57  		if name == "all" {
    58  			s.data = make(map[string]nothing)
    59  			return
    60  		}
    61  		delete(s.data, name)
    62  	}
    63  }
    64  
    65  // Union returns of Set of elements of both s and b.
    66  func (s *Set) Union(b *Set) *Set {
    67  	data := make(map[string]nothing)
    68  	for c := range s.data {
    69  		data[c] = null
    70  	}
    71  	for c := range b.data {
    72  		data[c] = null
    73  	}
    74  	return &Set{data: data}
    75  }
    76  
    77  // Difference returns the Set of elements of b not in s.
    78  func (s *Set) Difference(b *Set) *Set {
    79  	data := make(map[string]nothing)
    80  	for c := range b.data {
    81  		if _, exists := s.data[c]; !exists {
    82  			data[c] = null
    83  		}
    84  	}
    85  	return &Set{data: data}
    86  }
    87  
    88  // Intersect returns the Set of elements in both s and b.
    89  func (s *Set) Intersect(b *Set) *Set {
    90  	data := make(map[string]nothing)
    91  	for c := range s.data {
    92  		if _, exists := b.data[c]; exists {
    93  			data[c] = null
    94  		}
    95  	}
    96  	return &Set{data: data}
    97  }
    98  
    99  // Empty return true if no capabilities exist in s.
   100  func (s *Set) Empty() bool {
   101  	return len(s.data) == 0
   102  }
   103  
   104  // String returns the normalized and sorted string representation of s.
   105  func (s *Set) String() string {
   106  	return strings.Join(s.Slice(false), ", ")
   107  }
   108  
   109  // Slice returns a sorted slice of capabilities in s.
   110  //
   111  // upper - indicates whether to uppercase and prefix capabilities with CAP_
   112  func (s *Set) Slice(upper bool) []string {
   113  	caps := make([]string, 0, len(s.data))
   114  	for c := range s.data {
   115  		if upper {
   116  			c = "CAP_" + strings.ToUpper(c)
   117  		}
   118  		caps = append(caps, c)
   119  	}
   120  	sort.Strings(caps)
   121  	return caps
   122  }
   123  
   124  // linux capabilities are often named in 4 possible ways - upper or lower case,
   125  // and with or without a CAP_ prefix
   126  //
   127  // since we must do comparisons on cap names, always normalize the names before
   128  // letting them into the Set data-structure
   129  func normalize(name string) string {
   130  	spaces := strings.TrimSpace(name)
   131  	lower := strings.ToLower(spaces)
   132  	trim := strings.TrimPrefix(lower, "cap_")
   133  	return trim
   134  }