1// +build go1.7
2
3// Package management provides the main API client to construct other clients
4// and make requests to the Microsoft Azure Service Management REST API.
5package management
6
7// Copyright 2017 Microsoft Corporation
8//
9//    Licensed under the Apache License, Version 2.0 (the "License");
10//    you may not use this file except in compliance with the License.
11//    You may obtain a copy of the License at
12//
13//        http://www.apache.org/licenses/LICENSE-2.0
14//
15//    Unless required by applicable law or agreed to in writing, software
16//    distributed under the License is distributed on an "AS IS" BASIS,
17//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18//    See the License for the specific language governing permissions and
19//    limitations under the License.
20
21import (
22	"errors"
23	"fmt"
24	"runtime"
25	"time"
26
27	"github.com/Azure/azure-sdk-for-go/version"
28)
29
30var (
31	DefaultUserAgent = userAgent()
32)
33
34const (
35	DefaultAzureManagementURL    = "https://management.core.windows.net"
36	DefaultOperationPollInterval = time.Second * 30
37	DefaultAPIVersion            = "2014-10-01"
38
39	errPublishSettingsConfiguration       = "PublishSettingsFilePath is set. Consequently ManagementCertificatePath and SubscriptionId must not be set."
40	errManagementCertificateConfiguration = "Both ManagementCertificatePath and SubscriptionId should be set, and PublishSettingsFilePath must not be set."
41	errParamNotSpecified                  = "Parameter %s is not specified."
42)
43
44type client struct {
45	publishSettings publishSettings
46	config          ClientConfig
47}
48
49// Client is the base Azure Service Management API client instance that
50// can be used to construct client instances for various services.
51type Client interface {
52	// SendAzureGetRequest sends a request to the management API using the HTTP GET method
53	// and returns the response body or an error.
54	SendAzureGetRequest(url string) ([]byte, error)
55
56	// SendAzurePostRequest sends a request to the management API using the HTTP POST method
57	// and returns the request ID or an error.
58	SendAzurePostRequest(url string, data []byte) (OperationID, error)
59
60	// SendAzurePostRequestWithReturnedResponse sends a request to the management API using
61	// the HTTP POST method and returns the response body or an error.
62	SendAzurePostRequestWithReturnedResponse(url string, data []byte) ([]byte, error)
63
64	// SendAzurePutRequest sends a request to the management API using the HTTP PUT method
65	// and returns the request ID or an error. The content type can be specified, however
66	// if an empty string is passed, the default of "application/xml" will be used.
67	SendAzurePutRequest(url, contentType string, data []byte) (OperationID, error)
68
69	// SendAzureDeleteRequest sends a request to the management API using the HTTP DELETE method
70	// and returns the request ID or an error.
71	SendAzureDeleteRequest(url string) (OperationID, error)
72
73	// GetOperationStatus gets the status of operation with given Operation ID.
74	// WaitForOperation utility method can be used for polling for operation status.
75	GetOperationStatus(operationID OperationID) (GetOperationStatusResponse, error)
76
77	// WaitForOperation polls the Azure API for given operation ID indefinitely
78	// until the operation is completed with either success or failure.
79	// It is meant to be used for waiting for the result of the methods that
80	// return an OperationID value (meaning a long running operation has started).
81	//
82	// Cancellation of the polling loop (for instance, timing out) is done through
83	// cancel channel. If the user does not want to cancel, a nil chan can be provided.
84	// To cancel the method, it is recommended to close the channel provided to this
85	// method.
86	//
87	// If the operation was not successful or cancelling is signaled, an error
88	// is returned.
89	WaitForOperation(operationID OperationID, cancel chan struct{}) error
90}
91
92// ClientConfig provides a configuration for use by a Client.
93type ClientConfig struct {
94	ManagementURL         string
95	OperationPollInterval time.Duration
96	UserAgent             string
97	APIVersion            string
98}
99
100// NewAnonymousClient creates a new azure.Client with no credentials set.
101func NewAnonymousClient() Client {
102	return client{}
103}
104
105// DefaultConfig returns the default client configuration used to construct
106// a client. This value can be used to make modifications on the default API
107// configuration.
108func DefaultConfig() ClientConfig {
109	return ClientConfig{
110		ManagementURL:         DefaultAzureManagementURL,
111		OperationPollInterval: DefaultOperationPollInterval,
112		APIVersion:            DefaultAPIVersion,
113		UserAgent:             DefaultUserAgent,
114	}
115}
116
117// NewClient creates a new Client using the given subscription ID and
118// management certificate.
119func NewClient(subscriptionID string, managementCert []byte) (Client, error) {
120	return NewClientFromConfig(subscriptionID, managementCert, DefaultConfig())
121}
122
123// NewClientFromConfig creates a new Client using a given ClientConfig.
124func NewClientFromConfig(subscriptionID string, managementCert []byte, config ClientConfig) (Client, error) {
125	return makeClient(subscriptionID, managementCert, config)
126}
127
128func makeClient(subscriptionID string, managementCert []byte, config ClientConfig) (Client, error) {
129	var c client
130
131	if subscriptionID == "" {
132		return c, errors.New("azure: subscription ID required")
133	}
134
135	if len(managementCert) == 0 {
136		return c, errors.New("azure: management certificate required")
137	}
138
139	publishSettings := publishSettings{
140		SubscriptionID:   subscriptionID,
141		SubscriptionCert: managementCert,
142		SubscriptionKey:  managementCert,
143	}
144
145	// Validate client configuration
146	switch {
147	case config.ManagementURL == "":
148		return c, errors.New("azure: base URL required")
149	case config.OperationPollInterval <= 0:
150		return c, errors.New("azure: operation polling interval must be a positive duration")
151	case config.APIVersion == "":
152		return c, errors.New("azure: client configuration must specify an API version")
153	case config.UserAgent == "":
154		config.UserAgent = DefaultUserAgent
155	}
156
157	return client{
158		publishSettings: publishSettings,
159		config:          config,
160	}, nil
161}
162
163func userAgent() string {
164	return fmt.Sprintf("Go/%s (%s-%s) Azure-SDK-For-Go/%s asm/%s",
165		runtime.Version(),
166		runtime.GOARCH,
167		runtime.GOOS,
168		version.Number,
169		DefaultAPIVersion)
170}
171