| Serge Bazanski | 1f78954 | 2024-05-22 14:01:50 +0200 | [diff] [blame^] | 1 | package node |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
| 5 | "regexp" |
| 6 | ) |
| 7 | |
| 8 | var ( |
| 9 | reLabelFirstLast = regexp.MustCompile(`^[a-zA-Z0-9]$`) |
| 10 | reLabelBody = regexp.MustCompile(`^[a-zA-Z0-9\-._]*$`) |
| 11 | |
| 12 | // ErrLabelEmpty is returned by ValidateLabel if the label key/value is not at |
| 13 | // least one character long. |
| 14 | ErrLabelEmpty = fmt.Errorf("empty") |
| 15 | // ErrLabelTooLong is returned by ValidateLabel if the label key/value is more |
| 16 | // than 63 characters long. |
| 17 | ErrLabelTooLong = fmt.Errorf("too long") |
| 18 | // ErrLabelInvalidFirstCharacter is returned by ValidateLabel if the label |
| 19 | // key/value contains an invalid character on the first position. |
| 20 | ErrLabelInvalidFirstCharacter = fmt.Errorf("first character not a letter or number") |
| 21 | // ErrLabelInvalidLastCharacter is returned by ValidateLabel if the label |
| 22 | // key/value contains an invalid character on the last position. |
| 23 | ErrLabelInvalidLastCharacter = fmt.Errorf("last character not a letter or number") |
| 24 | // ErrLabelInvalidCharacter is returned by ValidateLabel if the label key/value |
| 25 | // contains an invalid character. |
| 26 | ErrLabelInvalidCharacter = fmt.Errorf("invalid character") |
| 27 | ) |
| 28 | |
| 29 | const ( |
| 30 | // MaxLabelsPerNode is the absolute maximum of labels that can be attached to a |
| 31 | // node. |
| 32 | MaxLabelsPerNode = 128 |
| 33 | ) |
| 34 | |
| 35 | // ValidateLabel ensures that a given node label key/value component is valid: |
| 36 | // |
| 37 | // 1. 1 to 63 characters long (inclusive); |
| 38 | // 2. Characters are all ASCII a-z A-Z 0-9 '_', '-' or '.'; |
| 39 | // 3. The first character is ASCII a-z A-Z or 0-9. |
| 40 | // 4. The last character is ASCII a-z A-Z or 0-9. |
| 41 | // |
| 42 | // If it's valid, nil is returned. Otherwise, one of ErrLabelEmpty, |
| 43 | // ErrLabelTooLong, ErrLabelInvalidFirstCharacter or ErrLabelInvalidCharacter is |
| 44 | // returned. |
| 45 | func ValidateLabel(v string) error { |
| 46 | if len(v) == 0 { |
| 47 | return ErrLabelEmpty |
| 48 | } |
| 49 | if len(v) > 63 { |
| 50 | return ErrLabelTooLong |
| 51 | } |
| 52 | if !reLabelFirstLast.MatchString(string(v[0])) { |
| 53 | return ErrLabelInvalidFirstCharacter |
| 54 | } |
| 55 | if !reLabelFirstLast.MatchString(string(v[len(v)-1])) { |
| 56 | return ErrLabelInvalidLastCharacter |
| 57 | } |
| 58 | // Body characters are a superset of the first/last characters, and we've already |
| 59 | // checked those so we can check the entire string here. |
| 60 | if !reLabelBody.MatchString(v) { |
| 61 | return ErrLabelInvalidCharacter |
| 62 | } |
| 63 | return nil |
| 64 | } |