Automatic merge from release/2.2.0 -> release/2.3.0

* commit '8512446cc4b651671df88ec40aa3291ccf99075b':
  服务未注册时,尝试注册服务
This commit is contained in:
邱剑
2018-11-19 13:43:49 +08:00
6 changed files with 239 additions and 29 deletions
+115 -28
View File
@@ -106,8 +106,10 @@ func (self *SAzureClient) getDefaultClient() (*autorest.Client, error) {
return nil, err
}
client.Authorizer = authorizer
// client.RequestInspector = LogRequest()
// client.ResponseInspector = LogResponse()
if DEBUG {
client.RequestInspector = LogRequest()
client.ResponseInspector = LogResponse()
}
return &client, nil
}
@@ -116,7 +118,7 @@ func (self *SAzureClient) jsonRequest(method, url string, body string) (jsonutil
if err != nil {
return nil, err
}
return jsonRequest(cli, method, self.domain, url, body)
return jsonRequest(cli, method, self.domain, url, self.subscriptionId, body)
}
func (self *SAzureClient) Get(resourceId string, params []string, retVal interface{}) error {
@@ -131,7 +133,7 @@ func (self *SAzureClient) Get(resourceId string, params []string, retVal interfa
if err != nil {
return err
}
body, err := jsonRequest(cli, "GET", self.domain, path, "")
body, err := jsonRequest(cli, "GET", self.domain, path, self.subscriptionId, "")
if err != nil {
return err
}
@@ -151,7 +153,7 @@ func (self *SAzureClient) ListVmSizes(location string) (jsonutils.JSONObject, er
return nil, fmt.Errorf("need subscription id")
}
url := fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Compute/locations/%s/vmSizes", self.subscriptionId, location)
return jsonRequest(cli, "GET", self.domain, url, "")
return jsonRequest(cli, "GET", self.domain, url, self.subscriptionId, "")
}
func (self *SAzureClient) ListClassicDisks() (jsonutils.JSONObject, error) {
@@ -163,7 +165,7 @@ func (self *SAzureClient) ListClassicDisks() (jsonutils.JSONObject, error) {
return nil, fmt.Errorf("need subscription id")
}
url := fmt.Sprintf("/subscriptions/%s/services/disks", self.subscriptionId)
return jsonRequest(cli, "GET", self.domain, url, "")
return jsonRequest(cli, "GET", self.domain, url, self.subscriptionId, "")
}
func (self *SAzureClient) ListAll(resourceType string, retVal interface{}) error {
@@ -178,7 +180,7 @@ func (self *SAzureClient) ListAll(resourceType string, retVal interface{}) error
if len(resourceType) > 0 {
url += fmt.Sprintf("/providers/%s", resourceType)
}
body, err := jsonRequest(cli, "GET", self.domain, url, "")
body, err := jsonRequest(cli, "GET", self.domain, url, self.subscriptionId, "")
if err != nil {
return err
}
@@ -193,7 +195,7 @@ func (self *SAzureClient) ListSubscriptions() (jsonutils.JSONObject, error) {
if err != nil {
return nil, err
}
return jsonRequest(cli, "GET", self.domain, "/subscriptions", "")
return jsonRequest(cli, "GET", self.domain, "/subscriptions", self.subscriptionId, "")
}
func (self *SAzureClient) List(golbalResource string, retVal interface{}) error {
@@ -208,7 +210,7 @@ func (self *SAzureClient) List(golbalResource string, retVal interface{}) error
if len(self.subscriptionId) > 0 && len(golbalResource) > 0 {
url += fmt.Sprintf("/%s", golbalResource)
}
body, err := jsonRequest(cli, "GET", self.domain, url, "")
body, err := jsonRequest(cli, "GET", self.domain, url, self.subscriptionId, "")
if err != nil {
return err
}
@@ -224,7 +226,7 @@ func (self *SAzureClient) ListByTypeWithResourceGroup(resourceGroupName string,
return fmt.Errorf("Missing subscription Info")
}
url := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/%s", self.subscriptionId, resourceGroupName, Type)
body, err := jsonRequest(cli, "GET", self.domain, url, "")
body, err := jsonRequest(cli, "GET", self.domain, url, self.subscriptionId, "")
if err != nil {
return err
}
@@ -236,7 +238,7 @@ func (self *SAzureClient) Delete(resourceId string) error {
if err != nil {
return err
}
_, err = jsonRequest(cli, "DELETE", self.domain, resourceId, "")
_, err = jsonRequest(cli, "DELETE", self.domain, resourceId, self.subscriptionId, "")
return err
}
@@ -246,7 +248,7 @@ func (self *SAzureClient) PerformAction(resourceId string, action string, body s
return nil, err
}
url := fmt.Sprintf("%s/%s", resourceId, action)
return jsonRequest(cli, "POST", self.domain, url, body)
return jsonRequest(cli, "POST", self.domain, url, self.subscriptionId, body)
}
func (self *SAzureClient) fetchResourceGroup(cli *autorest.Client, location string) error {
@@ -261,7 +263,7 @@ func (self *SAzureClient) fetchResourceGroup(cli *autorest.Client, location stri
if len(self.ressourceGroups) == 0 {
//Create Default resourceGroup
_url := fmt.Sprintf("/subscriptions/%s/resourcegroups/Default", self.subscriptionId)
body, err := jsonRequest(cli, "PUT", self.domain, _url, fmt.Sprintf(`{"name": "Default", "location": "%s"}`, location))
body, err := jsonRequest(cli, "PUT", self.domain, _url, self.subscriptionId, fmt.Sprintf(`{"name": "Default", "location": "%s"}`, location))
if err != nil {
return err
}
@@ -287,6 +289,18 @@ func (self *SAzureClient) checkParams(body jsonutils.JSONObject, params []string
return result, nil
}
type AzureErrorDetail struct {
Code string `json:"code,omitempty"`
Message string `json:"message,omitempty"`
Target string `json:"target,omitempty"`
}
type AzureError struct {
Code string `json:"code,omitempty"`
Details []AzureErrorDetail `json:"details,omitempty"`
Message string `json:"message,omitempty"`
}
func (self *SAzureClient) Create(body jsonutils.JSONObject, retVal interface{}) error {
cli, err := self.getDefaultClient()
if err != nil {
@@ -307,11 +321,14 @@ func (self *SAzureClient) Create(body jsonutils.JSONObject, retVal interface{})
return fmt.Errorf("Create Default resourceGroup error?")
}
url := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/%s/%s", self.subscriptionId, self.ressourceGroups[0].Name, params["type"], params["name"])
result, err := jsonRequest(cli, "PUT", self.domain, url, body.String())
result, err := jsonRequest(cli, "PUT", self.domain, url, self.subscriptionId, body.String())
if err != nil {
return err
}
return result.Unmarshal(retVal)
if retVal != nil {
return result.Unmarshal(retVal)
}
return nil
}
func (self *SAzureClient) CheckNameAvailability(Type string, body string) (jsonutils.JSONObject, error) {
@@ -323,7 +340,7 @@ func (self *SAzureClient) CheckNameAvailability(Type string, body string) (jsonu
return nil, fmt.Errorf("Missing subscription ID")
}
url := fmt.Sprintf("/subscriptions/%s/providers/%s/checkNameAvailability", self.subscriptionId, Type)
return jsonRequest(cli, "POST", self.domain, url, body)
return jsonRequest(cli, "POST", self.domain, url, self.subscriptionId, body)
}
func (self *SAzureClient) Update(body jsonutils.JSONObject, retVal interface{}) error {
@@ -332,7 +349,7 @@ func (self *SAzureClient) Update(body jsonutils.JSONObject, retVal interface{})
return err
}
url, err := body.GetString("id")
result, err := jsonRequest(cli, "PUT", self.domain, url, body.String())
result, err := jsonRequest(cli, "PUT", self.domain, url, self.subscriptionId, body.String())
if err != nil {
return err
}
@@ -342,8 +359,86 @@ func (self *SAzureClient) Update(body jsonutils.JSONObject, retVal interface{})
return nil
}
func jsonRequest(client *autorest.Client, method, domain, baseUrl string, body string) (jsonutils.JSONObject, error) {
return _jsonRequest(client, method, domain, baseUrl, body)
func waitRegisterComplete(client *autorest.Client, domain, subscriptionId string, serviceType string) error {
for i := 1; i < 10; i++ {
result, err := _jsonRequest(client, "GET", domain, fmt.Sprintf("/subscriptions/%s/providers", subscriptionId), "")
if err != nil {
return err
}
value, err := result.GetArray("value")
if err != nil {
return err
}
for _, v := range value {
namespace, _ := v.GetString("namespace")
if namespace == serviceType {
state, _ := v.GetString("registrationState")
if state == "Registered" {
return nil
}
log.Debugf("service %s state %s waite %d second ...", serviceType, state, i*10)
}
}
time.Sleep(time.Second * time.Duration(i*10))
}
return fmt.Errorf("wait service %s register timeout", serviceType)
}
func registerService(client *autorest.Client, domain, subscriptionId string, serviceType string) error {
registryUrl := fmt.Sprintf("/subscriptions/%s/providers/%s/register", subscriptionId, serviceType)
result, err := _jsonRequest(client, "POST", domain, registryUrl, "")
if err != nil || result.Contains("error") {
return fmt.Errorf("failed to register %s service", serviceType)
}
if state, _ := result.GetString("registrationState"); state == "Registered" {
return nil
}
return waitRegisterComplete(client, domain, subscriptionId, serviceType)
}
func recoverFromError(client *autorest.Client, domain, subscriptionId string, azureErr AzureError) bool {
switch azureErr.Code {
case "SubscriptionNotRegistered":
services := []string{"Microsoft.Network"}
for _, service := range services {
if err := registerService(client, domain, subscriptionId, service); err != nil {
log.Errorf("register %s error: %v", service, err)
return false
}
}
return true
case "MissingSubscriptionRegistration":
for _, detail := range azureErr.Details {
log.Errorf("The subscription is not registered to use namespace '%s', try register it", detail.Target)
if err := registerService(client, domain, subscriptionId, detail.Target); err != nil {
log.Errorf("register %s error: %v", detail.Target, err)
return false
}
}
return true
default:
return false
}
return false
}
func jsonRequest(client *autorest.Client, method, domain, baseUrl string, subscriptionId string, body string) (jsonutils.JSONObject, error) {
result, err := _jsonRequest(client, method, domain, baseUrl, body)
if err != nil {
return nil, err
}
if result.Contains("error") {
azureError := AzureError{}
if err := result.Unmarshal(&azureError, "error"); err != nil {
return nil, fmt.Errorf(result.String())
}
if recoverFromError(client, domain, subscriptionId, azureError) {
return _jsonRequest(client, method, domain, baseUrl, body)
}
log.Errorf("Azure %s request: %s \nbody: %s error: %v", method, baseUrl, body, result.String())
return nil, fmt.Errorf(result.String())
}
return result, nil
}
func waitForComplatetion(client *autorest.Client, req *http.Request, resp *http.Response, timeout time.Duration) (jsonutils.JSONObject, error) {
@@ -470,15 +565,7 @@ func _jsonRequest(client *autorest.Client, method, domain, baseURL, body string)
return nil, err
}
_data := strings.Replace(string(data), "\r", "", -1)
result, err = jsonutils.Parse([]byte(_data))
if err != nil {
return nil, err
}
if result.Contains("error") {
log.Errorf("Azure %s request: %s \nbody: %s error: %v", req.Method, req.URL.String(), body, result.String())
return nil, fmt.Errorf(result.String())
}
return result, nil
return jsonutils.Parse([]byte(_data))
}
func (self *SAzureClient) UpdateAccount(tenantId, secret, envName string) error {
+4
View File
@@ -9,6 +9,10 @@ import (
"github.com/Azure/go-autorest/autorest"
)
const (
DEBUG = false
)
func LogRequest() autorest.PrepareDecorator {
return func(p autorest.Preparer) autorest.Preparer {
return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) {
+55
View File
@@ -0,0 +1,55 @@
package azure
import (
"fmt"
)
type SServices struct {
Value []SService `json:"value,omitempty"`
}
type SService struct {
ID string `json:"id,omitempty"`
Namespace string `json:"namespace,omitempty"`
RegistrationState string `json:"registrationState,omitempty"`
ResourceTypes []ResourceType `json:"resourceTypes,omitempty"`
}
type ResourceType struct {
ApiVersions []string `json:"apiVersions,omitempty"`
Capabilities string `json:"capabilities,omitempty"`
Locations []string `json:"locations,omitempty"`
ResourceType string `json:"locations,omitempty"`
}
func (self *SRegion) ListServices() ([]SService, error) {
services := []SService{}
return services, self.client.List("providers", &services)
}
func (self *SRegion) SerciceShow(serviceType string) (*SService, error) {
service := SService{}
return &service, self.client.Get("providers/"+serviceType, []string{}, &service)
}
func (self *SRegion) serviceOperation(resourceType, operation string) error {
services, err := self.ListServices()
if err != nil {
return err
}
for _, service := range services {
if service.Namespace == resourceType {
_, err := self.client.jsonRequest("POST", fmt.Sprintf("%s/%s", service.ID, operation), "")
return err
}
}
return fmt.Errorf("failed to find namespace: %s", resourceType)
}
func (self *SRegion) ServiceRegister(resourceType string) error {
return self.serviceOperation(resourceType, "register")
}
func (self *SRegion) ServiceUnRegister(resourceType string) error {
return self.serviceOperation(resourceType, "unregister")
}
+41
View File
@@ -0,0 +1,41 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/azure"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type ServiceListOptions struct {
}
shellutils.R(&ServiceListOptions{}, "service-list", "List providers", func(cli *azure.SRegion, args *ServiceListOptions) error {
services, err := cli.ListServices()
if err != nil {
return err
}
printList(services, len(services), 0, 0, []string{})
return nil
})
type ServiceOptions struct {
NAME string `help:"Name for service register"`
}
shellutils.R(&ServiceOptions{}, "service-register", "Register service", func(cli *azure.SRegion, args *ServiceOptions) error {
return cli.ServiceRegister(args.NAME)
})
shellutils.R(&ServiceOptions{}, "service-unregister", "Unregister service", func(cli *azure.SRegion, args *ServiceOptions) error {
return cli.ServiceUnRegister(args.NAME)
})
shellutils.R(&ServiceOptions{}, "service-show", "Show service detail", func(cli *azure.SRegion, args *ServiceOptions) error {
service, err := cli.SerciceShow(args.NAME)
if err != nil {
return err
}
printObject(service)
return nil
})
}
+19
View File
@@ -32,4 +32,23 @@ func init() {
printObject(vpc)
return nil
})
shellutils.R(&VpcOptions{}, "vpc-delete", "Delete vpc", func(cli *azure.SRegion, args *VpcOptions) error {
return cli.DeleteVpc(args.ID)
})
type VpcCreateOptions struct {
NAME string `help:"vpc Name"`
CIDR string `help:"vpc cidr"`
Desc string `help:"vpc description"`
}
shellutils.R(&VpcCreateOptions{}, "vpc-create", "Create vpc", func(cli *azure.SRegion, args *VpcCreateOptions) error {
vpc, err := cli.CreateIVpc(args.NAME, args.Desc, args.CIDR)
if err != nil {
return err
}
printObject(vpc)
return nil
})
}
+5 -1
View File
@@ -77,7 +77,11 @@ func (self *SVpc) GetCidrBlock() string {
}
func (self *SVpc) Delete() error {
return self.region.client.Delete(self.ID)
return self.region.DeleteVpc(self.ID)
}
func (self *SRegion) DeleteVpc(vpcId string) error {
return self.client.Delete(vpcId)
}
func (self *SVpc) getSecurityGroups() ([]SSecurityGroup, error) {