github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/provider/azure/internal/ad/client.go (about) 1 // This file is based on code from Azure/azure-sdk-for-go 2 // and Azure/go-autorest, which are both 3 // Copyright Microsoft Corporation. See the LICENSE 4 // file in this directory for details. 5 // 6 // NOTE(axw) this file contains a client for a subset of the 7 // Microsoft Graph API, which is not currently supported by 8 // the Azure SDK. When it is, this will be deleted. 9 10 package ad 11 12 import ( 13 "fmt" 14 "io/ioutil" 15 "net/http" 16 17 "github.com/Azure/go-autorest/autorest" 18 "github.com/Azure/go-autorest/autorest/azure" 19 20 "github.com/juju/juju/version" 21 ) 22 23 const ( 24 // APIVersion is the version of the Active Directory API 25 APIVersion = "1.6" 26 ) 27 28 func UserAgent() string { 29 return "Juju/" + version.Current.String() 30 } 31 32 type ManagementClient struct { 33 autorest.Client 34 BaseURI string 35 APIVersion string 36 } 37 38 func NewManagementClient(baseURI string) ManagementClient { 39 return ManagementClient{ 40 Client: autorest.NewClientWithUserAgent(UserAgent()), 41 BaseURI: baseURI, 42 APIVersion: APIVersion, 43 } 44 } 45 46 // WithOdataErrorUnlessStatusCode returns a RespondDecorator that emits an 47 // azure.RequestError by reading the response body unless the response HTTP status code 48 // is among the set passed. 49 // 50 // If there is a chance service may return responses other than the Azure error 51 // format and the response cannot be parsed into an error, a decoding error will 52 // be returned containing the response body. In any case, the Responder will 53 // return an error if the status code is not satisfied. 54 // 55 // If this Responder returns an error, the response body will be replaced with 56 // an in-memory reader, which needs no further closing. 57 // 58 // NOTE(axw) this function is based on go-autorest/autorest/azure.WithErrorUnlessStatusCode. 59 // The only difference is that we extract "odata.error", instead of "error", 60 // from the response body; and we do not extract the message, which is in a 61 // different format for odata.error, and irrelevant to us. 62 func WithOdataErrorUnlessStatusCode(codes ...int) autorest.RespondDecorator { 63 return func(r autorest.Responder) autorest.Responder { 64 return autorest.ResponderFunc(func(resp *http.Response) error { 65 err := r.Respond(resp) 66 if err == nil && !autorest.ResponseHasStatusCode(resp, codes...) { 67 var oe odataRequestError 68 defer resp.Body.Close() 69 70 // Copy and replace the Body in case it does not contain an error object. 71 // This will leave the Body available to the caller. 72 b, decodeErr := autorest.CopyAndDecode(autorest.EncodedAsJSON, resp.Body, &oe) 73 resp.Body = ioutil.NopCloser(&b) 74 if decodeErr != nil { 75 return fmt.Errorf("ad: error response cannot be parsed: %q error: %v", b.String(), decodeErr) 76 } else if oe.ServiceError == nil { 77 oe.ServiceError = &odataServiceError{Code: "Unknown"} 78 } 79 80 e := azure.RequestError{ 81 ServiceError: &azure.ServiceError{Code: oe.ServiceError.Code}, 82 RequestID: azure.ExtractRequestID(resp), 83 } 84 if e.StatusCode == nil { 85 e.StatusCode = resp.StatusCode 86 } 87 err = &e 88 } 89 return err 90 }) 91 } 92 } 93 94 type odataRequestError struct { 95 ServiceError *odataServiceError `json:"odata.error"` 96 } 97 98 type odataServiceError struct { 99 Code string `json:"code"` 100 }