yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/hcso/hcso.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 "context" 19 "fmt" 20 "net/http" 21 "net/url" 22 "strconv" 23 "strings" 24 25 "github.com/huaweicloud/huaweicloud-sdk-go/auth/aksk" 26 27 "yunion.io/x/jsonutils" 28 "yunion.io/x/pkg/errors" 29 "yunion.io/x/pkg/gotypes" 30 31 "yunion.io/x/cloudmux/pkg/cloudprovider" 32 "yunion.io/x/onecloud/pkg/util/httputils" 33 ) 34 35 type akClient struct { 36 client *http.Client 37 aksk aksk.SignOptions 38 } 39 40 func (self *akClient) Do(req *http.Request) (*http.Response, error) { 41 req.Header.Del("Accept") 42 if req.Method == string(httputils.GET) || req.Method == string(httputils.DELETE) || req.Method == string(httputils.PATCH) { 43 req.Header.Del("Content-Length") 44 } 45 aksk.Sign(req, self.aksk) 46 return self.client.Do(req) 47 } 48 49 func (self *SHuaweiClient) getAkClient() *akClient { 50 return &akClient{ 51 client: self.getDefaultClient(), 52 aksk: aksk.SignOptions{ 53 AccessKey: self.accessKey, 54 SecretKey: self.accessSecret, 55 }, 56 } 57 } 58 59 func (self *SHuaweiClient) getDefaultClient() *http.Client { 60 if self.httpClient != nil { 61 return self.httpClient 62 } 63 self.httpClient = self.cpcfg.AdaptiveTimeoutHttpClient() 64 ts, _ := self.httpClient.Transport.(*http.Transport) 65 self.httpClient.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) { 66 service, method, path := strings.Split(req.URL.Host, ".")[0], req.Method, req.URL.Path 67 respCheck := func(resp *http.Response) { 68 if resp.StatusCode == 403 { 69 if self.cpcfg.UpdatePermission != nil { 70 self.cpcfg.UpdatePermission(service, fmt.Sprintf("%s %s", method, path)) 71 } 72 } 73 } 74 if self.cpcfg.ReadOnly { 75 if req.Method == "GET" { 76 return respCheck, nil 77 } 78 return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path) 79 } 80 return respCheck, nil 81 }) 82 return self.httpClient 83 } 84 85 func (self *SHuaweiClient) request(method httputils.THttpMethod, url string, query url.Values, params map[string]interface{}) (jsonutils.JSONObject, error) { 86 client := self.getAkClient() 87 if len(query) > 0 { 88 url = fmt.Sprintf("%s?%s", url, query.Encode()) 89 } 90 var body jsonutils.JSONObject = nil 91 if len(params) > 0 { 92 body = jsonutils.Marshal(params) 93 } 94 header := http.Header{} 95 if len(self.projectId) > 0 { 96 header.Set("X-Project-Id", self.projectId) 97 } 98 if strings.Contains(url, "/OS-CREDENTIAL/credentials") && len(self.ownerId) > 0 { 99 header.Set("X-Domain-Id", self.ownerId) 100 } 101 _, resp, err := httputils.JSONRequest(client, context.Background(), method, url, header, body, self.debug) 102 if err != nil { 103 if e, ok := err.(*httputils.JSONClientError); ok && e.Code == 404 { 104 return nil, errors.Wrapf(cloudprovider.ErrNotFound, err.Error()) 105 } 106 return nil, err 107 } 108 return resp, err 109 } 110 111 func (self *SHuaweiClient) resetEndpoint(endpoint, serviceName string) string { 112 if len(endpoint) == 0 { 113 domain := self.HuaweiClientConfig.endpoints.EndpointDomain 114 regionId := self.HuaweiClientConfig.cpcfg.DefaultRegion 115 if len(regionId) == 0 { 116 regionId = self.GetRegions()[0].ID 117 } 118 endpoint = fmt.Sprintf("%s.%s.%s", serviceName, regionId, domain) 119 } 120 return endpoint 121 } 122 123 func (self *SHuaweiClient) getAKSKList(userId string) (jsonutils.JSONObject, error) { 124 endpoint := self.resetEndpoint(self.endpoints.Iam, "iam-pub") 125 uri := fmt.Sprintf("https://%s/v3.0/OS-CREDENTIAL/credentials", endpoint) 126 query := url.Values{} 127 query.Set("user_id", userId) 128 return self.request(httputils.GET, uri, query, nil) 129 } 130 131 func (self *SHuaweiClient) createAKSK(params map[string]interface{}) (jsonutils.JSONObject, error) { 132 endpoint := self.resetEndpoint(self.endpoints.Iam, "iam-pub") 133 uri := fmt.Sprintf("https://%s/v3.0/OS-CREDENTIAL/credentials", endpoint) 134 return self.request(httputils.POST, uri, nil, params) 135 } 136 137 func (self *SHuaweiClient) deleteAKSK(accessKey string) (jsonutils.JSONObject, error) { 138 endpoint := self.resetEndpoint(self.endpoints.Iam, "iam-pub") 139 uri := fmt.Sprintf("https://%s/v3.0/OS-CREDENTIAL/credentials/%s", endpoint, accessKey) 140 return self.request(httputils.DELETE, uri, nil, nil) 141 } 142 143 func (self *SHuaweiClient) modelartsPoolNetworkList(params map[string]interface{}) (jsonutils.JSONObject, error) { 144 endpoint := self.resetEndpoint(self.endpoints.Modelarts, "modelarts") 145 uri := fmt.Sprintf("https://%s/v1/%s/networks", endpoint, self.projectId) 146 return self.request(httputils.GET, uri, url.Values{}, params) 147 } 148 149 func (self *SHuaweiClient) modelartsPoolNetworkCreate(params map[string]interface{}) (jsonutils.JSONObject, error) { 150 endpoint := self.resetEndpoint(self.endpoints.Modelarts, "modelarts") 151 uri := fmt.Sprintf("https://%s/v1/%s/networks", endpoint, self.projectId) 152 return self.request(httputils.POST, uri, url.Values{}, params) 153 } 154 155 func (self *SHuaweiClient) modelartsPoolById(poolName string) (jsonutils.JSONObject, error) { 156 endpoint := self.resetEndpoint(self.endpoints.Modelarts, "modelarts") 157 uri := fmt.Sprintf("https://%s/v2/%s/pools/%s", endpoint, self.projectId, poolName) 158 return self.request(httputils.GET, uri, url.Values{}, nil) 159 } 160 161 func (self *SHuaweiClient) modelartsPoolList(params map[string]interface{}) (jsonutils.JSONObject, error) { 162 endpoint := self.resetEndpoint(self.endpoints.Modelarts, "modelarts") 163 uri := fmt.Sprintf("https://%s/v2/%s/pools", endpoint, self.projectId) 164 return self.request(httputils.GET, uri, url.Values{}, params) 165 } 166 167 func (self *SHuaweiClient) modelartsPoolCreate(params map[string]interface{}) (jsonutils.JSONObject, error) { 168 endpoint := self.resetEndpoint(self.endpoints.Modelarts, "modelarts") 169 uri := fmt.Sprintf("https://%s/v2/%s/pools", endpoint, self.projectId) 170 return self.request(httputils.POST, uri, url.Values{}, params) 171 } 172 173 func (self *SHuaweiClient) modelartsPoolDelete(poolName string, params map[string]interface{}) (jsonutils.JSONObject, error) { 174 endpoint := self.resetEndpoint(self.endpoints.Modelarts, "modelarts") 175 uri := fmt.Sprintf("https://%s/v2/%s/pools/%s", endpoint, self.projectId, poolName) 176 return self.request(httputils.DELETE, uri, url.Values{}, params) 177 } 178 179 func (self *SHuaweiClient) modelartsPoolUpdate(poolName string, params map[string]interface{}) (jsonutils.JSONObject, error) { 180 endpoint := self.resetEndpoint(self.endpoints.Modelarts, "modelarts") 181 uri := fmt.Sprintf("https://%s/v2/%s/pools/%s", endpoint, self.projectId, poolName) 182 urlValue := url.Values{} 183 urlValue.Add("time_range", "") 184 urlValue.Add("statistics", "") 185 urlValue.Add("period", "") 186 return self.patchRequest(httputils.PATCH, uri, urlValue, params) 187 } 188 189 func (self *SHuaweiClient) modelartsPoolMonitor(poolName string, params map[string]interface{}) (jsonutils.JSONObject, error) { 190 endpoint := self.resetEndpoint(self.endpoints.Modelarts, "modelarts") 191 uri := fmt.Sprintf("https://%s/v2/%s/pools/%s/monitor", endpoint, self.projectId, poolName) 192 return self.request(httputils.GET, uri, url.Values{}, params) 193 } 194 195 func (self *SHuaweiClient) modelartsResourceflavors(params map[string]interface{}) (jsonutils.JSONObject, error) { 196 endpoint := self.resetEndpoint(self.endpoints.Modelarts, "modelarts") 197 uri := fmt.Sprintf("https://%s/v1/%s/resourceflavors", endpoint, self.projectId) 198 return self.request(httputils.GET, uri, url.Values{}, params) 199 } 200 201 func (self *SHuaweiClient) patchRequest(method httputils.THttpMethod, url string, query url.Values, params map[string]interface{}) (jsonutils.JSONObject, error) { 202 client := self.getAkClient() 203 if len(query) > 0 { 204 url = fmt.Sprintf("%s?%s", url, query.Encode()) 205 } 206 var body jsonutils.JSONObject = nil 207 if len(params) > 0 { 208 body = jsonutils.Marshal(params) 209 } 210 header := http.Header{} 211 if len(self.projectId) > 0 { 212 header.Set("X-Project-Id", self.projectId) 213 } 214 var bodystr string 215 if !gotypes.IsNil(body) { 216 bodystr = body.String() 217 } 218 jbody := strings.NewReader(bodystr) 219 header.Set("Content-Length", strconv.FormatInt(int64(len(bodystr)), 10)) 220 header.Set("Content-Type", "application/merge-patch+json") 221 resp, err := httputils.Request(client, context.Background(), method, url, header, jbody, self.debug) 222 _, respValue, err := httputils.ParseJSONResponse(bodystr, resp, err, self.debug) 223 if err != nil { 224 if e, ok := err.(*httputils.JSONClientError); ok && e.Code == 404 { 225 return nil, errors.Wrapf(cloudprovider.ErrNotFound, err.Error()) 226 } 227 return nil, err 228 } 229 return respValue, err 230 }