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