yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/hcso/utils.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 hcso 16 17 import ( 18 "fmt" 19 "reflect" 20 "strings" 21 22 "yunion.io/x/jsonutils" 23 "yunion.io/x/log" 24 "yunion.io/x/pkg/errors" 25 "yunion.io/x/pkg/utils" 26 27 "yunion.io/x/onecloud/pkg/util/httputils" 28 29 "yunion.io/x/cloudmux/pkg/cloudprovider" 30 "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" 31 "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses" 32 ) 33 34 // 常用的方法 35 type listFunc func(querys map[string]string) (*responses.ListResult, error) 36 type getFunc func(id string, querys map[string]string) (jsonutils.JSONObject, error) 37 type createFunc func(params jsonutils.JSONObject) (jsonutils.JSONObject, error) 38 type updateFunc func(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) 39 type updateFunc2 func(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) 40 type deleteFunc func(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) 41 type deleteFunc2 func(ctx manager.IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) 42 type listInCtxFunc func(ctx manager.IManagerContext, querys map[string]string) (*responses.ListResult, error) 43 type listInCtxWithSpecFunc func(ctx manager.IManagerContext, spec string, querys map[string]string, responseKey string) (*responses.ListResult, error) 44 45 func unmarshalResult(resp jsonutils.JSONObject, respErr error, result interface{}, method string) error { 46 if respErr != nil { 47 switch e := respErr.(type) { 48 case *httputils.JSONClientError: 49 if (e.Code == 404 || utils.IsInStringArray(e.Class, NOT_FOUND_CODES)) && method != "POST" { 50 return cloudprovider.ErrNotFound 51 } 52 return e 53 default: 54 return e 55 } 56 } 57 58 if result == nil { 59 return nil 60 } 61 62 err := resp.Unmarshal(result) 63 if err != nil { 64 log.Errorf("unmarshal json error %s", err) 65 } 66 67 return err 68 } 69 70 var pageLimit = 100 71 72 // offset 表示的是页码 73 func doListAllWithPagerOffset(doList listFunc, queries map[string]string, result interface{}) error { 74 startIndex := 0 75 resultValue := reflect.Indirect(reflect.ValueOf(result)) 76 queries["limit"] = fmt.Sprintf("%d", pageLimit) 77 queries["offset"] = fmt.Sprintf("%d", startIndex) 78 for { 79 total, part, err := doListPart(doList, queries, result) 80 if err != nil { 81 return err 82 } 83 if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { 84 break 85 } 86 87 startIndex++ 88 queries["offset"] = fmt.Sprintf("%d", startIndex) 89 } 90 return nil 91 } 92 93 func doListAllWithNextLink(doList listFunc, querys map[string]string, result interface{}) error { 94 values := []jsonutils.JSONObject{} 95 for { 96 ret, err := doList(querys) 97 if err != nil { 98 return errors.Wrap(err, "doList") 99 } 100 values = append(values, ret.Data...) 101 if len(ret.NextLink) == 0 || ret.NextLink == "null" { 102 break 103 } 104 } 105 if result != nil { 106 return jsonutils.Update(result, values) 107 } 108 return nil 109 } 110 111 func doListAllWithOffset(doList listFunc, queries map[string]string, result interface{}) error { 112 startIndex := 0 113 resultValue := reflect.Indirect(reflect.ValueOf(result)) 114 queries["limit"] = fmt.Sprintf("%d", pageLimit) 115 queries["offset"] = fmt.Sprintf("%d", startIndex) 116 for { 117 total, part, err := doListPart(doList, queries, result) 118 if err != nil { 119 return err 120 } 121 if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { 122 break 123 } 124 queries["offset"] = fmt.Sprintf("%d", startIndex+resultValue.Len()) 125 } 126 return nil 127 } 128 129 func doListAllWithPage(doList listFunc, queries map[string]string, result interface{}) error { 130 startIndex := 1 131 resultValue := reflect.Indirect(reflect.ValueOf(result)) 132 queries["limit"] = fmt.Sprintf("%d", pageLimit) 133 queries["page"] = fmt.Sprintf("%d", startIndex) 134 for { 135 total, part, err := doListPart(doList, queries, result) 136 if err != nil { 137 return err 138 } 139 if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { 140 break 141 } 142 queries["page"] = fmt.Sprintf("%d", startIndex+resultValue.Len()) 143 } 144 return nil 145 } 146 147 func doListAllWithMarker(doList listFunc, queries map[string]string, result interface{}) error { 148 resultValue := reflect.Indirect(reflect.ValueOf(result)) 149 queries["limit"] = fmt.Sprintf("%d", pageLimit) 150 for { 151 total, part, err := doListPart(doList, queries, result) 152 if err != nil { 153 return err 154 } 155 if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { 156 break 157 } 158 lastValue := resultValue.Index(resultValue.Len() - 1) 159 markerValue := lastValue.FieldByNameFunc(func(key string) bool { 160 if strings.ToLower(key) == "id" { 161 return true 162 } 163 return false 164 }) 165 queries["marker"] = markerValue.String() 166 } 167 return nil 168 } 169 170 func doListAll(doList listFunc, queries map[string]string, result interface{}) error { 171 total, _, err := doListPart(doList, queries, result) 172 if err != nil { 173 return err 174 } 175 resultValue := reflect.Indirect(reflect.ValueOf(result)) 176 if total > 0 && resultValue.Len() < total { 177 log.Warningf("INCOMPLETE QUERY, total %d queried %d", total, resultValue.Len()) 178 } 179 return nil 180 } 181 182 func doListPart(doList listFunc, queries map[string]string, result interface{}) (int, int, error) { 183 ret, err := doList(queries) 184 if err != nil { 185 return 0, 0, err 186 } 187 resultValue := reflect.Indirect(reflect.ValueOf(result)) 188 elemType := resultValue.Type().Elem() 189 for i := range ret.Data { 190 elemPtr := reflect.New(elemType) 191 err = ret.Data[i].Unmarshal(elemPtr.Interface()) 192 if err != nil { 193 return 0, 0, err 194 } 195 resultValue.Set(reflect.Append(resultValue, elemPtr.Elem())) 196 } 197 return ret.Total, len(ret.Data), nil 198 } 199 200 func DoGet(doGet getFunc, id string, queries map[string]string, result interface{}) error { 201 if len(id) == 0 { 202 resultType := reflect.Indirect(reflect.ValueOf(result)).Type() 203 return errors.Wrap(cloudprovider.ErrNotFound, fmt.Sprintf(" Get %s id should not be empty", resultType.Name())) 204 } 205 206 ret, err := doGet(id, queries) 207 return unmarshalResult(ret, err, result, "GET") 208 } 209 210 func DoListInContext(listFunc listInCtxFunc, ctx manager.IManagerContext, querys map[string]string, result interface{}) error { 211 ret, err := listFunc(ctx, querys) 212 if err != nil { 213 return err 214 } 215 216 obj := responses.ListResult2JSON(ret) 217 err = obj.Unmarshal(result, "data") 218 if err != nil { 219 log.Errorf("unmarshal json error %s", err) 220 return err 221 } 222 223 return nil 224 } 225 226 func DoCreate(createFunc createFunc, params jsonutils.JSONObject, result interface{}) error { 227 ret, err := createFunc(params) 228 return unmarshalResult(ret, err, result, "POST") 229 } 230 231 func DoUpdate(updateFunc updateFunc, id string, params jsonutils.JSONObject, result interface{}) error { 232 ret, err := updateFunc(id, params) 233 return unmarshalResult(ret, err, result, "PUT") 234 } 235 236 func DoUpdateWithSpec(updateFunc updateFunc2, id string, spec string, params jsonutils.JSONObject) error { 237 _, err := updateFunc(nil, id, spec, params, "") 238 return err 239 } 240 241 func DoUpdateWithSpec2(updateFunc updateFunc2, id string, spec string, params jsonutils.JSONObject, result interface{}) error { 242 ret, err := updateFunc(nil, id, spec, params, "") 243 return unmarshalResult(ret, err, result, "PUT") 244 } 245 246 func DoDelete(deleteFunc deleteFunc, id string, params jsonutils.JSONObject, result interface{}) error { 247 if len(id) == 0 { 248 return fmt.Errorf(" id should not be empty") 249 } 250 251 ret, err := deleteFunc(id, params) 252 return unmarshalResult(ret, err, result, "DELETE") 253 } 254 255 func DoDeleteWithSpec(deleteFunc deleteFunc2, ctx manager.IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject) error { 256 if len(id) == 0 { 257 return fmt.Errorf(" id should not be empty") 258 } 259 260 _, err := deleteFunc(ctx, id, spec, queries, params, "") 261 return err 262 } 263 264 func ErrMessage(err error) string { 265 switch v := err.(type) { 266 case *httputils.JSONClientError: 267 return fmt.Sprintf("%d(%s):%s", v.Code, v.Class, v.Details) 268 default: 269 return err.Error() 270 } 271 }