opts.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. package opts
  2. import (
  3. "fmt"
  4. "math/big"
  5. "net"
  6. "regexp"
  7. "strings"
  8. "github.com/docker/docker/api/types/filters"
  9. )
  10. var (
  11. alphaRegexp = regexp.MustCompile(`[a-zA-Z]`)
  12. domainRegexp = regexp.MustCompile(`^(:?(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]))(:?\.(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])))*)\.?\s*$`)
  13. )
  14. // ListOpts holds a list of values and a validation function.
  15. type ListOpts struct {
  16. values *[]string
  17. validator ValidatorFctType
  18. }
  19. // NewListOpts creates a new ListOpts with the specified validator.
  20. func NewListOpts(validator ValidatorFctType) ListOpts {
  21. var values []string
  22. return *NewListOptsRef(&values, validator)
  23. }
  24. // NewListOptsRef creates a new ListOpts with the specified values and validator.
  25. func NewListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts {
  26. return &ListOpts{
  27. values: values,
  28. validator: validator,
  29. }
  30. }
  31. func (opts *ListOpts) String() string {
  32. return fmt.Sprintf("%v", []string((*opts.values)))
  33. }
  34. // Set validates if needed the input value and adds it to the
  35. // internal slice.
  36. func (opts *ListOpts) Set(value string) error {
  37. if opts.validator != nil {
  38. v, err := opts.validator(value)
  39. if err != nil {
  40. return err
  41. }
  42. value = v
  43. }
  44. (*opts.values) = append((*opts.values), value)
  45. return nil
  46. }
  47. // Delete removes the specified element from the slice.
  48. func (opts *ListOpts) Delete(key string) {
  49. for i, k := range *opts.values {
  50. if k == key {
  51. (*opts.values) = append((*opts.values)[:i], (*opts.values)[i+1:]...)
  52. return
  53. }
  54. }
  55. }
  56. // GetMap returns the content of values in a map in order to avoid
  57. // duplicates.
  58. func (opts *ListOpts) GetMap() map[string]struct{} {
  59. ret := make(map[string]struct{})
  60. for _, k := range *opts.values {
  61. ret[k] = struct{}{}
  62. }
  63. return ret
  64. }
  65. // GetAll returns the values of slice.
  66. func (opts *ListOpts) GetAll() []string {
  67. return (*opts.values)
  68. }
  69. // GetAllOrEmpty returns the values of the slice
  70. // or an empty slice when there are no values.
  71. func (opts *ListOpts) GetAllOrEmpty() []string {
  72. v := *opts.values
  73. if v == nil {
  74. return make([]string, 0)
  75. }
  76. return v
  77. }
  78. // Get checks the existence of the specified key.
  79. func (opts *ListOpts) Get(key string) bool {
  80. for _, k := range *opts.values {
  81. if k == key {
  82. return true
  83. }
  84. }
  85. return false
  86. }
  87. // Len returns the amount of element in the slice.
  88. func (opts *ListOpts) Len() int {
  89. return len((*opts.values))
  90. }
  91. // Type returns a string name for this Option type
  92. func (opts *ListOpts) Type() string {
  93. return "list"
  94. }
  95. // NamedOption is an interface that list and map options
  96. // with names implement.
  97. type NamedOption interface {
  98. Name() string
  99. }
  100. // NamedListOpts is a ListOpts with a configuration name.
  101. // This struct is useful to keep reference to the assigned
  102. // field name in the internal configuration struct.
  103. type NamedListOpts struct {
  104. name string
  105. ListOpts
  106. }
  107. var _ NamedOption = &NamedListOpts{}
  108. // NewNamedListOptsRef creates a reference to a new NamedListOpts struct.
  109. func NewNamedListOptsRef(name string, values *[]string, validator ValidatorFctType) *NamedListOpts {
  110. return &NamedListOpts{
  111. name: name,
  112. ListOpts: *NewListOptsRef(values, validator),
  113. }
  114. }
  115. // Name returns the name of the NamedListOpts in the configuration.
  116. func (o *NamedListOpts) Name() string {
  117. return o.name
  118. }
  119. // MapOpts holds a map of values and a validation function.
  120. type MapOpts struct {
  121. values map[string]string
  122. validator ValidatorFctType
  123. }
  124. // Set validates if needed the input value and add it to the
  125. // internal map, by splitting on '='.
  126. func (opts *MapOpts) Set(value string) error {
  127. if opts.validator != nil {
  128. v, err := opts.validator(value)
  129. if err != nil {
  130. return err
  131. }
  132. value = v
  133. }
  134. vals := strings.SplitN(value, "=", 2)
  135. if len(vals) == 1 {
  136. (opts.values)[vals[0]] = ""
  137. } else {
  138. (opts.values)[vals[0]] = vals[1]
  139. }
  140. return nil
  141. }
  142. // GetAll returns the values of MapOpts as a map.
  143. func (opts *MapOpts) GetAll() map[string]string {
  144. return opts.values
  145. }
  146. func (opts *MapOpts) String() string {
  147. return fmt.Sprintf("%v", map[string]string((opts.values)))
  148. }
  149. // Type returns a string name for this Option type
  150. func (opts *MapOpts) Type() string {
  151. return "map"
  152. }
  153. // NewMapOpts creates a new MapOpts with the specified map of values and a validator.
  154. func NewMapOpts(values map[string]string, validator ValidatorFctType) *MapOpts {
  155. if values == nil {
  156. values = make(map[string]string)
  157. }
  158. return &MapOpts{
  159. values: values,
  160. validator: validator,
  161. }
  162. }
  163. // NamedMapOpts is a MapOpts struct with a configuration name.
  164. // This struct is useful to keep reference to the assigned
  165. // field name in the internal configuration struct.
  166. type NamedMapOpts struct {
  167. name string
  168. MapOpts
  169. }
  170. var _ NamedOption = &NamedMapOpts{}
  171. // NewNamedMapOpts creates a reference to a new NamedMapOpts struct.
  172. func NewNamedMapOpts(name string, values map[string]string, validator ValidatorFctType) *NamedMapOpts {
  173. return &NamedMapOpts{
  174. name: name,
  175. MapOpts: *NewMapOpts(values, validator),
  176. }
  177. }
  178. // Name returns the name of the NamedMapOpts in the configuration.
  179. func (o *NamedMapOpts) Name() string {
  180. return o.name
  181. }
  182. // ValidatorFctType defines a validator function that returns a validated string and/or an error.
  183. type ValidatorFctType func(val string) (string, error)
  184. // ValidatorFctListType defines a validator function that returns a validated list of string and/or an error
  185. type ValidatorFctListType func(val string) ([]string, error)
  186. // ValidateIPAddress validates an Ip address.
  187. func ValidateIPAddress(val string) (string, error) {
  188. var ip = net.ParseIP(strings.TrimSpace(val))
  189. if ip != nil {
  190. return ip.String(), nil
  191. }
  192. return "", fmt.Errorf("%s is not an ip address", val)
  193. }
  194. // ValidateDNSSearch validates domain for resolvconf search configuration.
  195. // A zero length domain is represented by a dot (.).
  196. func ValidateDNSSearch(val string) (string, error) {
  197. if val = strings.Trim(val, " "); val == "." {
  198. return val, nil
  199. }
  200. return validateDomain(val)
  201. }
  202. func validateDomain(val string) (string, error) {
  203. if alphaRegexp.FindString(val) == "" {
  204. return "", fmt.Errorf("%s is not a valid domain", val)
  205. }
  206. ns := domainRegexp.FindSubmatch([]byte(val))
  207. if len(ns) > 0 && len(ns[1]) < 255 {
  208. return string(ns[1]), nil
  209. }
  210. return "", fmt.Errorf("%s is not a valid domain", val)
  211. }
  212. // ValidateLabel validates that the specified string is a valid label, and returns it.
  213. // Labels are in the form on key=value.
  214. func ValidateLabel(val string) (string, error) {
  215. if strings.Count(val, "=") < 1 {
  216. return "", fmt.Errorf("bad attribute format: %s", val)
  217. }
  218. return val, nil
  219. }
  220. // ValidateSysctl validates a sysctl and returns it.
  221. func ValidateSysctl(val string) (string, error) {
  222. validSysctlMap := map[string]bool{
  223. "kernel.msgmax": true,
  224. "kernel.msgmnb": true,
  225. "kernel.msgmni": true,
  226. "kernel.sem": true,
  227. "kernel.shmall": true,
  228. "kernel.shmmax": true,
  229. "kernel.shmmni": true,
  230. "kernel.shm_rmid_forced": true,
  231. }
  232. validSysctlPrefixes := []string{
  233. "net.",
  234. "fs.mqueue.",
  235. }
  236. arr := strings.Split(val, "=")
  237. if len(arr) < 2 {
  238. return "", fmt.Errorf("sysctl '%s' is not whitelisted", val)
  239. }
  240. if validSysctlMap[arr[0]] {
  241. return val, nil
  242. }
  243. for _, vp := range validSysctlPrefixes {
  244. if strings.HasPrefix(arr[0], vp) {
  245. return val, nil
  246. }
  247. }
  248. return "", fmt.Errorf("sysctl '%s' is not whitelisted", val)
  249. }
  250. // FilterOpt is a flag type for validating filters
  251. type FilterOpt struct {
  252. filter filters.Args
  253. }
  254. // NewFilterOpt returns a new FilterOpt
  255. func NewFilterOpt() FilterOpt {
  256. return FilterOpt{filter: filters.NewArgs()}
  257. }
  258. func (o *FilterOpt) String() string {
  259. repr, err := filters.ToParam(o.filter)
  260. if err != nil {
  261. return "invalid filters"
  262. }
  263. return repr
  264. }
  265. // Set sets the value of the opt by parsing the command line value
  266. func (o *FilterOpt) Set(value string) error {
  267. var err error
  268. o.filter, err = filters.ParseFlag(value, o.filter)
  269. return err
  270. }
  271. // Type returns the option type
  272. func (o *FilterOpt) Type() string {
  273. return "filter"
  274. }
  275. // Value returns the value of this option
  276. func (o *FilterOpt) Value() filters.Args {
  277. return o.filter
  278. }
  279. // NanoCPUs is a type for fixed point fractional number.
  280. type NanoCPUs int64
  281. // String returns the string format of the number
  282. func (c *NanoCPUs) String() string {
  283. return big.NewRat(c.Value(), 1e9).FloatString(3)
  284. }
  285. // Set sets the value of the NanoCPU by passing a string
  286. func (c *NanoCPUs) Set(value string) error {
  287. cpus, err := ParseCPUs(value)
  288. *c = NanoCPUs(cpus)
  289. return err
  290. }
  291. // Type returns the type
  292. func (c *NanoCPUs) Type() string {
  293. return "decimal"
  294. }
  295. // Value returns the value in int64
  296. func (c *NanoCPUs) Value() int64 {
  297. return int64(*c)
  298. }
  299. // ParseCPUs takes a string ratio and returns an integer value of nano cpus
  300. func ParseCPUs(value string) (int64, error) {
  301. cpu, ok := new(big.Rat).SetString(value)
  302. if !ok {
  303. return 0, fmt.Errorf("failed to parse %v as a rational number", value)
  304. }
  305. nano := cpu.Mul(cpu, big.NewRat(1e9, 1))
  306. if !nano.IsInt() {
  307. return 0, fmt.Errorf("value is too precise")
  308. }
  309. return nano.Num().Int64(), nil
  310. }