diff --git a/cmd/climc/shell/cloudaccounts.go b/cmd/climc/shell/cloudaccounts.go index 558e6cc14d..78a3cbf568 100644 --- a/cmd/climc/shell/cloudaccounts.go +++ b/cmd/climc/shell/cloudaccounts.go @@ -45,7 +45,7 @@ func init() { AuthURL string `help:"OpenStack auth_url"` Host string `help:"VMware host"` Port string `help:"VMware host port" default:"443"` - directoryID string `help:"Azure directory_id"` + DirectoryID string `help:"Azure directory_id"` ClientID string `help:"Azure client_id"` ClientSecret string `help:"Azure clinet_secret"` Environment string `help:"Azure|Huawei|Aws environment" choices:"AzureGermanCloud|AzureChinaCloud|AzureUSGovernmentCloud|AzurePublicCloud|InternationalCloud|ChinaCloud|"` diff --git a/pkg/cloudcommon/db/tenantcache.go b/pkg/cloudcommon/db/tenantcache.go index c16394a2d6..ee42bc40fc 100644 --- a/pkg/cloudcommon/db/tenantcache.go +++ b/pkg/cloudcommon/db/tenantcache.go @@ -8,9 +8,12 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/consts" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" + "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/mcclient/modules" + + "yunion.io/x/onecloud/pkg/util/httputils" ) type STenantCacheManager struct { @@ -82,6 +85,9 @@ func (manager *STenantCacheManager) fetchTenantFromKeystone(ctx context.Context, s := auth.GetAdminSession(ctx, consts.GetRegion(), "v1") tenant, err := modules.Projects.Get(s, idStr, nil) if err != nil { + if je, ok := err.(*httputils.JSONClientError); ok && je.Code == 404 { + return nil, sql.ErrNoRows + } log.Errorf("fetch project fail %s", err) return nil, err } diff --git a/pkg/compute/models/cloudproviders.go b/pkg/compute/models/cloudproviders.go index 9b6072191f..a0da013c15 100644 --- a/pkg/compute/models/cloudproviders.go +++ b/pkg/compute/models/cloudproviders.go @@ -587,7 +587,7 @@ func (self *SCloudprovider) getMoreDetails(ctx context.Context, extra *jsonutils } account := self.GetCloudaccount() if account != nil { - extra.Add(jsonutils.NewString(account.GetName()), "account") + extra.Add(jsonutils.NewString(account.GetName()), "cloudaccount") } return extra } diff --git a/pkg/compute/models/loadbalancers.go b/pkg/compute/models/loadbalancers.go index 8052c24d6f..83a91a3b22 100644 --- a/pkg/compute/models/loadbalancers.go +++ b/pkg/compute/models/loadbalancers.go @@ -352,21 +352,40 @@ func (man *SLoadbalancerManager) newFromCloudLoadbalancer(ctx context.Context, u log.Errorf("newFromCloudRegion fail %s", err) return nil, err } + lb.syncLoadbalancerNetwork(ctx, userCred) return &lb, nil } +func (lb *SLoadbalancer) syncLoadbalancerNetwork(ctx context.Context, userCred mcclient.TokenCredential) { + if len(lb.NetworkId) > 0 { + lbNetReq := &SLoadbalancerNetworkRequestData{ + loadbalancer: lb, + networkId: lb.NetworkId, + address: lb.Address, + } + _, err := LoadbalancernetworkManager.NewLoadbalancerNetwork(ctx, userCred, lbNetReq) + if err != nil { + log.Errorf("failed to create loadbalancer network: %v", err) + } + } +} + func (lb *SLoadbalancer) SyncWithCloudLoadbalancer(ctx context.Context, userCred mcclient.TokenCredential, extLb cloudprovider.ICloudLoadbalancer, projectId string, projectSync bool) error { _, err := lb.GetModelManager().TableSpec().Update(lb, func() error { lb.Address = extLb.GetAddress() lb.Status = extLb.GetStatus() lb.Name = extLb.GetName() - + if networkId := extLb.GetNetworkId(); len(networkId) > 0 { + if network, err := NetworkManager.FetchByExternalId(networkId); err == nil && network != nil { + lb.NetworkId = network.GetId() + } + } if projectSync && len(projectId) > 0 { lb.ProjectId = projectId } - return nil }) + lb.syncLoadbalancerNetwork(ctx, userCred) return err } diff --git a/pkg/util/aliyun/loadbalancer.go b/pkg/util/aliyun/loadbalancer.go index 1000d723ca..221f7b3d50 100644 --- a/pkg/util/aliyun/loadbalancer.go +++ b/pkg/util/aliyun/loadbalancer.go @@ -97,7 +97,7 @@ func (lb *SLoadbalancer) GetNetworkType() string { } func (lb *SLoadbalancer) GetNetworkId() string { - return "" + return lb.VSwitchId } func (lb *SLoadbalancer) GetZoneId() string { diff --git a/pkg/util/httputils/httputils.go b/pkg/util/httputils/httputils.go index fb0fb3c988..1c25800484 100644 --- a/pkg/util/httputils/httputils.go +++ b/pkg/util/httputils/httputils.go @@ -54,8 +54,13 @@ type JSONClientError struct { Data Error } +type JSONClientErrorMsg struct { + Error *JSONClientError +} + func (e *JSONClientError) Error() string { - return fmt.Sprintf("JSONClientError: %s %d %s", e.Details, e.Code, e.Class) + errMsg := JSONClientErrorMsg{Error: e} + return jsonutils.Marshal(errMsg).String() } func headerExists(header *http.Header, key string) bool { @@ -224,34 +229,45 @@ func ParseJSONResponse(resp *http.Response, err error, debug bool) (http.Header, ce.Class = "redirect" return nil, nil, &ce } else { - ce := JSONClientError{} + ce := JSONClientError{ + Code: resp.StatusCode, + Details: resp.Status, + } if jrbody == nil { - ce.Code = resp.StatusCode - ce.Details = resp.Status return nil, nil, &ce } - jrbody2, err := jrbody.Get("error") - if err == nil { - ecode, err := jrbody2.Int("code") - if err == nil { - ce.Code = int(ecode) - ce.Details, _ = jrbody2.GetString("message") - ce.Class, _ = jrbody2.GetString("title") - return nil, nil, &ce - } else { - ce.Code = resp.StatusCode - ce.Details = jrbody2.String() - return nil, nil, &ce + jrbody1, err := jrbody.GetMap() + if err != nil { + err = jrbody.Unmarshal(&ce) + if err != nil { + ce.Details = err.Error() + } + return nil, nil, &ce + } + var jrbody2 jsonutils.JSONObject + if len(jrbody1) > 1 { + jrbody2 = jsonutils.Marshal(jrbody1) + } else { + for _, v := range jrbody1 { + jrbody2 = v } } - - err = jrbody.Unmarshal(&ce) - if err != nil { - return nil, nil, err - } else { - return nil, nil, &ce + if ecode, _ := jrbody2.GetString("code"); len(ecode) > 0 { + code, err := strconv.Atoi(ecode) + if err != nil { + ce.Class = ecode + } else { + ce.Code = code + } } + if edetail := jsonutils.GetAnyString(jrbody2, []string{"message", "detail", "error_msg"}); len(edetail) > 0 { + ce.Details = edetail + } + if eclass := jsonutils.GetAnyString(jrbody2, []string{"title", "type", "error_code"}); len(eclass) > 0 { + ce.Class = eclass + } + return nil, nil, &ce } } diff --git a/pkg/util/httputils/httputils_test.go b/pkg/util/httputils/httputils_test.go new file mode 100644 index 0000000000..a9957a1abc --- /dev/null +++ b/pkg/util/httputils/httputils_test.go @@ -0,0 +1,113 @@ +package httputils + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "yunion.io/x/jsonutils" +) + +type SErrorMsg struct { + statusCode int + Code string + Message string + Title string + Type string + ErrorCode string + ErrorMsg string + result JSONClientErrorMsg +} + +func TestError(t *testing.T) { + + for testName, msg := range map[string]SErrorMsg{ + "test1": { + statusCode: 400, + Code: "VPC.0601", + Message: "Securitygroup id is invalid.", + Title: "", + Type: "", + result: JSONClientErrorMsg{ + Error: &JSONClientError{ + Code: 400, + Class: "VPC.0601", + Details: "Securitygroup id is invalid.", + }, + }, + }, + "test2": { + statusCode: 400, + Code: "3435", + Message: "Securitygroup id is invalid.", + Title: "", + Type: "", + result: JSONClientErrorMsg{ + Error: &JSONClientError{ + Code: 3435, + Class: "", + Details: "Securitygroup id is invalid.", + }, + }, + }, + "test3": { + statusCode: 400, + ErrorCode: "APIGW.0301", + ErrorMsg: "Incorrect IAM authentication information: verify aksk signature fail", + result: JSONClientErrorMsg{ + Error: &JSONClientError{ + Code: 400, + Class: "APIGW.0301", + Details: "Incorrect IAM authentication information: verify aksk signature fail", + }, + }, + }, + } { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(msg.statusCode) + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(jsonutils.Marshal(msg).String())) + })) + _, _, err := JSONRequest(ts.Client(), context.Background(), THttpMethod("GET"), ts.URL, nil, nil, true) + if err != nil { + respErr := JSONClientErrorMsg{} + if err := json.Unmarshal([]byte(err.Error()), &respErr); err != nil { + t.Error(err) + } + if msg.result.Error.Class != respErr.Error.Class { + t.Errorf("expect %s class %s not %s", testName, msg.result.Error.Class, respErr.Error.Class) + } + if msg.result.Error.Code != respErr.Error.Code { + t.Errorf("expect %s code %d not %d", testName, msg.result.Error.Code, respErr.Error.Code) + } + if msg.result.Error.Details != respErr.Error.Details { + t.Errorf("expect %s detail %s not %s", testName, msg.result.Error.Class, respErr.Error.Class) + } + } + + ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(msg.statusCode) + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(jsonutils.Marshal(map[string]SErrorMsg{"error": msg}).String())) + })) + _, _, err = JSONRequest(ts.Client(), context.Background(), THttpMethod("GET"), ts.URL, nil, nil, true) + if err != nil { + respErr := JSONClientErrorMsg{} + if err := json.Unmarshal([]byte(err.Error()), &respErr); err != nil { + t.Error(err) + } + if msg.result.Error.Class != respErr.Error.Class { + t.Errorf("expect %s class %s not %s", testName, msg.result.Error.Class, respErr.Error.Class) + } + if msg.result.Error.Code != respErr.Error.Code { + t.Errorf("expect %s code %d not %d", testName, msg.result.Error.Code, respErr.Error.Code) + } + if msg.result.Error.Details != respErr.Error.Details { + t.Errorf("expect %s detail %s not %s", testName, msg.result.Error.Class, respErr.Error.Class) + } + } + + } +}