Skip to content

Commit

Permalink
Add support for clouds other than public (#13496)
Browse files Browse the repository at this point in the history
* Add support for clouds other than public

Renamed DefaultEndpoint to AzurePublicCloud.
Added const for the sovereign clouds.
Construct token scope based on the cloud.
Updated NewRPRegistrationPolicy() to take an endpoint param.

* rename func per feedback
  • Loading branch information
jhendrixMSFT authored Nov 13, 2020
1 parent 2dde7b8 commit bba4720
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 23 deletions.
32 changes: 24 additions & 8 deletions sdk/armcore/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,21 @@ import (
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
)

const scope = "https://management.azure.com//.default"
const defaultScope = "/.default"

const (
// AzureChina is the Azure Resourece Manager China cloud endpoint.
AzureChina = "https://management.chinacloudapi.cn/"
// AzureGermany is the Azure Resourece Manager Germany cloud endpoint.
AzureGermany = "https://management.microsoftazure.de/"
// AzureGovernment is the Azure Resourece Manager US government cloud endpoint.
AzureGovernment = "https://management.usgovcloudapi.net/"
// AzurePublicCloud is the Azure Resourece Manager public cloud endpoint.
AzurePublicCloud = "https://management.azure.com/"
)

// ConnectionOptions contains configuration settings for the connection's pipeline.
// Call DefaultConnectionOptions() to create an instance populated with default values.
type ConnectionOptions struct {
// HTTPClient sets the transport for making HTTP requests.
HTTPClient azcore.Transport
Expand Down Expand Up @@ -39,12 +51,9 @@ type Connection struct {
p azcore.Pipeline
}

// DefaultEndpoint is the Azure Resourece Manager public cloud endpoint.
const DefaultEndpoint = "https://management.azure.com"

// NewDefaultConnection creates an instance of the Connection type using the DefaultEndpoint.
// NewDefaultConnection creates an instance of the Connection type using the AzurePublicCloud.
func NewDefaultConnection(cred azcore.TokenCredential, options *ConnectionOptions) *Connection {
return NewConnection(DefaultEndpoint, cred, options)
return NewConnection(AzurePublicCloud, cred, options)
}

// NewConnection creates an instance of the Connection type with the specified endpoint.
Expand All @@ -56,9 +65,9 @@ func NewConnection(endpoint string, cred azcore.TokenCredential, options *Connec
}
p := azcore.NewPipeline(options.HTTPClient,
azcore.NewTelemetryPolicy(&options.Telemetry),
NewRPRegistrationPolicy(cred, &options.RegisterRPOptions),
NewRPRegistrationPolicy(endpoint, cred, &options.RegisterRPOptions),
azcore.NewRetryPolicy(&options.Retry),
cred.AuthenticationPolicy(azcore.AuthenticationPolicyOptions{Options: azcore.TokenRequestOptions{Scopes: []string{scope}}}),
cred.AuthenticationPolicy(azcore.AuthenticationPolicyOptions{Options: azcore.TokenRequestOptions{Scopes: []string{endpointToScope(endpoint)}}}),
azcore.NewLogPolicy(nil))
return NewConnectionWithPipeline(endpoint, p)
}
Expand All @@ -78,3 +87,10 @@ func (c *Connection) Endpoint() string {
func (c *Connection) Pipeline() azcore.Pipeline {
return c.p
}

func endpointToScope(endpoint string) string {
if endpoint[len(endpoint)-1] != '/' {
endpoint += "/"
}
return endpoint + defaultScope
}
11 changes: 10 additions & 1 deletion sdk/armcore/connection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (mockTokenCred) GetToken(context.Context, azcore.TokenRequestOptions) (*azc
func TestNewDefaultConnection(t *testing.T) {
opt := DefaultConnectionOptions()
con := NewDefaultConnection(mockTokenCred{}, &opt)
if ep := con.Endpoint(); ep != DefaultEndpoint {
if ep := con.Endpoint(); ep != AzurePublicCloud {
t.Fatalf("unexpected endpoint %s", ep)
}
}
Expand Down Expand Up @@ -64,3 +64,12 @@ func TestNewConnectionWithPipeline(t *testing.T) {
t.Fatalf("unexpected status code: %d", resp.StatusCode)
}
}

func TestScope(t *testing.T) {
if s := endpointToScope(AzureGermany); s != "https://management.microsoftazure.de//.default" {
t.Fatalf("unexpected scope %s", s)
}
if s := endpointToScope("https://management.usgovcloudapi.net"); s != "https://management.usgovcloudapi.net//.default" {
t.Fatalf("unexpected scope %s", s)
}
}
16 changes: 9 additions & 7 deletions sdk/armcore/policy_register_rp.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const (
)

// RegistrationOptions configures the registration policy's behavior.
// Call DefaultRegistrationOptions() to create an instance populated with default values.
type RegistrationOptions struct {
// MaxAttempts is the total number of times to attempt automatic registration
// in the event that an attempt fails.
Expand Down Expand Up @@ -60,24 +61,25 @@ func DefaultRegistrationOptions() RegistrationOptions {
}
}

// NewRPRegistrationPolicy creates a policy object configured using the specified pipeline
// and options. The policy controls if an unregistered resource provider should automatically
// be registered. See https://aka.ms/rps-not-found for more information.
// NewRPRegistrationPolicy creates a policy object configured using the specified endpoint,
// credentials and options. The policy controls if an unregistered resource provider should
// automatically be registered. See https://aka.ms/rps-not-found for more information.
// Pass nil to accept the default options; this is the same as passing the result
// from a call to DefaultRegistrationOptions().
func NewRPRegistrationPolicy(cred azcore.Credential, o *RegistrationOptions) azcore.Policy {
func NewRPRegistrationPolicy(endpoint string, cred azcore.Credential, o *RegistrationOptions) azcore.Policy {
if o == nil {
def := DefaultRegistrationOptions()
o = &def
}
p := azcore.NewPipeline(o.HTTPClient,
azcore.NewRetryPolicy(&o.Retry),
cred.AuthenticationPolicy(azcore.AuthenticationPolicyOptions{Options: azcore.TokenRequestOptions{Scopes: []string{scope}}}),
cred.AuthenticationPolicy(azcore.AuthenticationPolicyOptions{Options: azcore.TokenRequestOptions{Scopes: []string{endpointToScope(endpoint)}}}),
azcore.NewLogPolicy(nil))
return &rpRegistrationPolicy{pipeline: p, options: *o}
return &rpRegistrationPolicy{endpoint: endpoint, pipeline: p, options: *o}
}

type rpRegistrationPolicy struct {
endpoint string
pipeline azcore.Pipeline
options RegistrationOptions
}
Expand Down Expand Up @@ -128,7 +130,7 @@ func (r *rpRegistrationPolicy) Do(req *azcore.Request) (*azcore.Response, error)
// we use the scheme and host from the original request
rpOps := &providersOperations{
p: r.pipeline,
u: fmt.Sprintf("%s://%s", req.URL.Scheme, req.URL.Host),
u: r.endpoint,
subID: subID,
}
if _, err = rpOps.Register(req.Context(), rp); err != nil {
Expand Down
14 changes: 7 additions & 7 deletions sdk/armcore/policy_register_rp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func TestRPRegistrationPolicySuccess(t *testing.T) {
srv.AppendResponse(mock.WithStatusCode(http.StatusOK), mock.WithBody([]byte(rpRegisteredResp)))
// response for original request (different status code than any of the other responses)
srv.AppendResponse(mock.WithStatusCode(http.StatusAccepted))
pl := azcore.NewPipeline(srv, NewRPRegistrationPolicy(azcore.AnonymousCredential(), testRPRegistrationOptions(srv)))
pl := azcore.NewPipeline(srv, NewRPRegistrationPolicy(srv.URL(), azcore.AnonymousCredential(), testRPRegistrationOptions(srv)))
req, err := azcore.NewRequest(context.Background(), http.MethodGet, azcore.JoinPaths(srv.URL(), requestEndpoint))
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -108,7 +108,7 @@ func TestRPRegistrationPolicyNA(t *testing.T) {
defer close()
// response indicates no RP registration is required, policy does nothing
srv.AppendResponse(mock.WithStatusCode(http.StatusOK))
pl := azcore.NewPipeline(srv, NewRPRegistrationPolicy(azcore.AnonymousCredential(), testRPRegistrationOptions(srv)))
pl := azcore.NewPipeline(srv, NewRPRegistrationPolicy(srv.URL(), azcore.AnonymousCredential(), testRPRegistrationOptions(srv)))
req, err := azcore.NewRequest(context.Background(), http.MethodGet, srv.URL())
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -147,7 +147,7 @@ func TestRPRegistrationPolicy409Other(t *testing.T) {
defer close()
// test getting a 409 but not due to registration required
srv.AppendResponse(mock.WithStatusCode(http.StatusConflict), mock.WithBody([]byte(failedResp)))
pl := azcore.NewPipeline(srv, NewRPRegistrationPolicy(azcore.AnonymousCredential(), testRPRegistrationOptions(srv)))
pl := azcore.NewPipeline(srv, NewRPRegistrationPolicy(srv.URL(), azcore.AnonymousCredential(), testRPRegistrationOptions(srv)))
req, err := azcore.NewRequest(context.Background(), http.MethodGet, srv.URL())
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -178,7 +178,7 @@ func TestRPRegistrationPolicyTimesOut(t *testing.T) {
// polling responses to Register() and Get(), in progress but slow
// tests registration takes too long, times out
srv.RepeatResponse(10, mock.WithStatusCode(http.StatusOK), mock.WithBody([]byte(rpRegisteringResp)), mock.WithSlowResponse(400*time.Millisecond))
pl := azcore.NewPipeline(srv, NewRPRegistrationPolicy(azcore.AnonymousCredential(), testRPRegistrationOptions(srv)))
pl := azcore.NewPipeline(srv, NewRPRegistrationPolicy(srv.URL(), azcore.AnonymousCredential(), testRPRegistrationOptions(srv)))
req, err := azcore.NewRequest(context.Background(), http.MethodGet, azcore.JoinPaths(srv.URL(), requestEndpoint))
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -222,7 +222,7 @@ func TestRPRegistrationPolicyExceedsAttempts(t *testing.T) {
// polling response, successful registration
srv.AppendResponse(mock.WithStatusCode(http.StatusOK), mock.WithBody([]byte(rpRegisteredResp)))
}
pl := azcore.NewPipeline(srv, NewRPRegistrationPolicy(azcore.AnonymousCredential(), testRPRegistrationOptions(srv)))
pl := azcore.NewPipeline(srv, NewRPRegistrationPolicy(srv.URL(), azcore.AnonymousCredential(), testRPRegistrationOptions(srv)))
req, err := azcore.NewRequest(context.Background(), http.MethodGet, azcore.JoinPaths(srv.URL(), requestEndpoint))
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -270,7 +270,7 @@ func TestRPRegistrationPolicyCanCancel(t *testing.T) {
srv.RepeatResponse(10, mock.WithStatusCode(http.StatusOK), mock.WithBody([]byte(rpRegisteringResp)), mock.WithSlowResponse(300*time.Millisecond))
opts := DefaultRegistrationOptions()
opts.HTTPClient = srv
pl := azcore.NewPipeline(srv, NewRPRegistrationPolicy(azcore.AnonymousCredential(), &opts))
pl := azcore.NewPipeline(srv, NewRPRegistrationPolicy(srv.URL(), azcore.AnonymousCredential(), &opts))
// log only RP registration
azcore.Log().SetClassifications(LogRPRegistration)
defer func() {
Expand Down Expand Up @@ -323,7 +323,7 @@ func TestRPRegistrationPolicyDisabled(t *testing.T) {
srv.AppendResponse(mock.WithStatusCode(http.StatusConflict), mock.WithBody([]byte(rpUnregisteredResp)))
ops := testRPRegistrationOptions(srv)
ops.MaxAttempts = 0
pl := azcore.NewPipeline(srv, NewRPRegistrationPolicy(azcore.AnonymousCredential(), ops))
pl := azcore.NewPipeline(srv, NewRPRegistrationPolicy(srv.URL(), azcore.AnonymousCredential(), ops))
req, err := azcore.NewRequest(context.Background(), http.MethodGet, azcore.JoinPaths(srv.URL(), requestEndpoint))
if err != nil {
t.Fatal(err)
Expand Down

0 comments on commit bba4720

Please sign in to comment.