yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/apsara/resource_tags.go (about) 1 // Copyright 2019 Yunion 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package apsara 16 17 import ( 18 "fmt" 19 20 "yunion.io/x/jsonutils" 21 "yunion.io/x/pkg/errors" 22 23 "yunion.io/x/cloudmux/pkg/cloudprovider" 24 ) 25 26 type STagResource struct { 27 ResourceType string `json:"ResourceType"` 28 TagValue string `json:"TagValue"` 29 ResourceID string `json:"ResourceId"` 30 TagKey string `json:"TagKey"` 31 } 32 33 func (self *SRegion) rawListTagResources(serviceType string, resourceType string, resIds []string, token string) ([]STagResource, string, error) { 34 if len(resIds) > 50 { 35 return nil, "", errors.Wrap(cloudprovider.ErrNotSupported, "resource count exceed 50 for one request") 36 } 37 params := make(map[string]string) 38 params["ResourceType"] = resourceType 39 for i := range resIds { 40 params[fmt.Sprintf("ResourceId.%d", i+1)] = resIds[i] 41 } 42 if len(token) != 0 { 43 params["NextToken"] = token 44 } 45 ret, err := self.tagRequest(serviceType, "ListTagResources", params) 46 if err != nil { 47 return nil, "", errors.Wrapf(err, `self.tagRequest(%s,"ListTagResources", %s)`, serviceType, jsonutils.Marshal(params).String()) 48 } 49 tagResources := []STagResource{} 50 err = ret.Unmarshal(&tagResources, "TagResources", "TagResource") 51 if err != nil { 52 return nil, "", errors.Wrapf(err, "(%s).Unmarshal(&tagResources)", ret.String()) 53 } 54 nextToken, _ := ret.GetString("NextToken") 55 return tagResources, nextToken, nil 56 } 57 58 func splitStringSlice(resIds []string, stride int) [][]string { 59 result := [][]string{} 60 i := 0 61 for i < len(resIds)/stride { 62 result = append(result, resIds[i*stride:i*stride+stride]) 63 i++ 64 } 65 remainder := len(resIds) % stride 66 if remainder != 0 { 67 result = append(result, resIds[i*stride:i*stride+remainder]) 68 } 69 return result 70 } 71 72 func splitTags(tags map[string]string, stride int) []map[string]string { 73 tagsGroups := []map[string]string{} 74 tagsGroup := map[string]string{} 75 for k, v := range tags { 76 tagsGroup[k] = v 77 if len(tagsGroup) == stride { 78 tagsGroups = append(tagsGroups, tagsGroup) 79 tagsGroup = map[string]string{} 80 } 81 } 82 if len(tagsGroup) > 0 { 83 tagsGroups = append(tagsGroups, tagsGroup) 84 } 85 return tagsGroups 86 } 87 88 func (self *SRegion) ListResourceTags(serviceType string, resourceType string, resIds []string) (map[string]*map[string]string, error) { 89 tags := make(map[string]*map[string]string) 90 tagReources := []STagResource{} 91 nextToken := "" 92 resIdsGroups := splitStringSlice(resIds, 50) 93 for i := range resIdsGroups { 94 for { 95 _tagResource, nextToken, err := self.rawListTagResources(serviceType, resourceType, resIdsGroups[i], nextToken) 96 if err != nil { 97 return nil, errors.Wrapf(err, "self.rawListTagResources(%s,%s,%s)", resourceType, resIds, nextToken) 98 } 99 tagReources = append(tagReources, _tagResource...) 100 if len(_tagResource) == 0 || len(nextToken) == 0 { 101 break 102 } 103 104 } 105 } 106 for _, r := range tagReources { 107 if tagMapPtr, ok := tags[r.ResourceID]; !ok { 108 tagMap := map[string]string{ 109 r.TagKey: r.TagValue, 110 } 111 tags[r.ResourceID] = &tagMap 112 } else { 113 tagMap := *tagMapPtr 114 tagMap[r.TagKey] = r.TagValue 115 } 116 } 117 return tags, nil 118 } 119 120 func (self *SRegion) rawTagResources(serviceType string, resourceType string, resIds []string, tags map[string]string) error { 121 if len(resIds) > 50 { 122 return errors.Wrap(cloudprovider.ErrNotSupported, "resource count exceed 50 for one request") 123 } 124 if len(tags) > 20 { 125 return errors.Wrap(cloudprovider.ErrNotSupported, "tags count exceed 20 for one request") 126 } 127 params := make(map[string]string) 128 params["ResourceType"] = resourceType 129 for i := range resIds { 130 params[fmt.Sprintf("ResourceId.%d", i+1)] = resIds[i] 131 } 132 i := 0 133 for k, v := range tags { 134 params[fmt.Sprintf("Tag.%d.Key", i+1)] = k 135 params[fmt.Sprintf("Tag.%d.Value", i+1)] = v 136 i++ 137 } 138 _, err := self.tagRequest(serviceType, "TagResources", params) 139 if err != nil { 140 return errors.Wrapf(err, `self.tagRequest(%s,"TagResources", %s)`, serviceType, jsonutils.Marshal(params).String()) 141 } 142 return nil 143 } 144 145 func (self *SRegion) TagResources(serviceType string, resourceType string, resIds []string, tags map[string]string) error { 146 if len(resIds) == 0 || len(tags) == 0 { 147 return nil 148 } 149 resIdsGroups := splitStringSlice(resIds, 50) 150 tagsGroups := splitTags(tags, 20) 151 for i := range resIdsGroups { 152 for j := range tagsGroups { 153 err := self.rawTagResources(serviceType, resourceType, resIdsGroups[i], tagsGroups[j]) 154 if err != nil { 155 return errors.Wrapf(err, "self.rawTagResources(resourceType, resIdsGroups[i], tagsGroups[i])") 156 } 157 } 158 } 159 return nil 160 } 161 162 func (self *SRegion) rawUntagResources(serviceType string, resourceType string, resIds []string, tags []string) error { 163 if len(resIds) > 50 { 164 return errors.Wrap(cloudprovider.ErrNotSupported, "resource count exceed 50 for one request") 165 } 166 if len(tags) > 20 { 167 return errors.Wrap(cloudprovider.ErrNotSupported, "tags count exceed 20 for one request") 168 } 169 params := make(map[string]string) 170 params["ResourceType"] = resourceType 171 for i := range resIds { 172 params[fmt.Sprintf("ResourceId.%d", i+1)] = resIds[i] 173 } 174 for i := range tags { 175 params[fmt.Sprintf("TagKey.%d", i+1)] = tags[i] 176 } 177 _, err := self.tagRequest(serviceType, "UntagResources", params) 178 if err != nil { 179 return errors.Wrapf(err, `self.tagRequest(%s,"UntagResources", %s)`, serviceType, jsonutils.Marshal(params).String()) 180 } 181 return nil 182 } 183 184 func (self *SRegion) UntagResources(serviceType string, resourceType string, resIds []string, tags []string) error { 185 if len(resIds) == 0 || len(tags) == 0 { 186 return nil 187 } 188 resIdsGroups := splitStringSlice(resIds, 50) 189 tagsGroups := splitStringSlice(tags, 20) 190 for i := range resIdsGroups { 191 for j := range tagsGroups { 192 err := self.rawUntagResources(serviceType, resourceType, resIdsGroups[i], tagsGroups[j]) 193 if err != nil { 194 return errors.Wrapf(err, "self.rawTagResources(resourceType, resIdsGroups[i], tagsGroups[i])") 195 } 196 } 197 } 198 return nil 199 } 200 201 func (self *SRegion) SetResourceTags(serviceType string, resourceType string, resIds []string, tags map[string]string, replace bool) error { 202 oldTags, err := self.ListResourceTags(serviceType, resourceType, resIds) 203 if err != nil { 204 return errors.Wrapf(err, "self.ListResourceTags(%s,%s)", resourceType, resIds) 205 } 206 for i := range resIds { 207 _, ok := oldTags[resIds[i]] 208 if !ok { 209 err := self.TagResources(serviceType, resourceType, []string{resIds[i]}, tags) 210 if err != nil { 211 return errors.Wrap(err, "self.TagResources(resourceType, []string{resIds[i]}, tags)") 212 } 213 } else { 214 oldResourceTags := *oldTags[resIds[i]] 215 addTags := map[string]string{} 216 for k, v := range tags { 217 if _, ok := oldResourceTags[k]; !ok { 218 addTags[k] = v 219 } else { 220 if oldResourceTags[k] != v { 221 addTags[k] = v 222 } 223 } 224 } 225 delTags := []string{} 226 if replace { 227 for k := range oldResourceTags { 228 if _, ok := tags[k]; !ok { 229 delTags = append(delTags, k) 230 } 231 } 232 } 233 err := self.UntagResources(serviceType, resourceType, []string{resIds[i]}, delTags) 234 if err != nil { 235 return errors.Wrap(err, "self.UntagResources(resourceType, []string{resIds[i]}, delTags)") 236 } 237 err = self.TagResources(serviceType, resourceType, []string{resIds[i]}, addTags) 238 if err != nil { 239 return errors.Wrap(err, "self.TagResources(resourceType, []string{resIds[i]}, addTags)") 240 } 241 } 242 } 243 return nil 244 }