vitess.io/vitess@v0.16.2/go/vt/vtorc/inst/tag.go (about) 1 /* 2 Copyright 2015 Shlomi Noach, courtesy Booking.com 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package inst 18 19 import ( 20 "fmt" 21 "regexp" 22 "strings" 23 ) 24 25 type Tag struct { 26 TagName string 27 TagValue string 28 HasValue bool 29 Negate bool 30 } 31 32 var ( 33 negateTagEqualsRegexp = regexp.MustCompile("^~([^=]+)=(.*)$") 34 TagEqualsRegexp = regexp.MustCompile("^([^=]+)=(.*)$") 35 negateTagExistsRegexp = regexp.MustCompile("^~([^=]+)$") 36 tagExistsRegexp = regexp.MustCompile("^([^=]+)$") 37 ) 38 39 func NewTag(tagName string, tagValue string) (*Tag, error) { 40 tagName = strings.TrimSpace(tagName) 41 if tagName == "" { 42 return nil, fmt.Errorf("NewTag: empty tag name") 43 } 44 return &Tag{TagName: tagName, TagValue: tagValue}, nil 45 } 46 47 func ParseTag(tagString string) (*Tag, error) { 48 tagString = strings.Replace(tagString, "!", "~", -1) 49 tagString = strings.TrimSpace(tagString) 50 51 if submatch := negateTagEqualsRegexp.FindStringSubmatch(tagString); len(submatch) > 0 { 52 return &Tag{ 53 TagName: submatch[1], 54 TagValue: submatch[2], 55 HasValue: true, 56 Negate: true, 57 }, nil 58 } else if submatch := TagEqualsRegexp.FindStringSubmatch(tagString); len(submatch) > 0 { 59 return &Tag{ 60 TagName: submatch[1], 61 TagValue: submatch[2], 62 HasValue: true, 63 }, nil 64 } else if submatch := negateTagExistsRegexp.FindStringSubmatch(tagString); len(submatch) > 0 { 65 return &Tag{ 66 TagName: submatch[1], 67 Negate: true, 68 }, nil 69 } else if submatch := tagExistsRegexp.FindStringSubmatch(tagString); len(submatch) > 0 { 70 return &Tag{ 71 TagName: submatch[1], 72 }, nil 73 } 74 return nil, fmt.Errorf("Unable to parse tag: %s", tagString) 75 } 76 77 func (tag *Tag) String() string { 78 return fmt.Sprintf("%s=%s", tag.TagName, tag.TagValue) 79 } 80 81 func (tag *Tag) Display() string { 82 if tag.TagValue == "" { 83 return tag.TagName 84 } 85 return fmt.Sprintf("%s=%s", tag.TagName, tag.TagValue) 86 } 87 88 func ParseIntersectTags(tagsString string) (tags [](*Tag), err error) { 89 for _, tagString := range strings.Split(tagsString, ",") { 90 tag, err := ParseTag(tagString) 91 if err != nil { 92 return tags, err 93 } 94 tags = append(tags, tag) 95 } 96 return tags, nil 97 } 98 99 type InstanceTag struct { 100 Key InstanceKey 101 T Tag 102 } 103 104 func GetInstanceKeysByTags(tagsString string) (tagged *InstanceKeyMap, err error) { 105 tags, err := ParseIntersectTags(tagsString) 106 if err != nil { 107 return tagged, err 108 } 109 for i, tag := range tags { 110 taggedByTag, err := GetInstanceKeysByTag(tag) 111 if err != nil { 112 return tagged, err 113 } 114 if i == 0 { 115 tagged = taggedByTag 116 } else { 117 tagged = tagged.Intersect(taggedByTag) 118 } 119 } 120 return tagged, nil 121 }