vendor: add github.com/Azure/azure-sdk-for-go and dependencies
This commit is contained in:
+10
@@ -0,0 +1,10 @@
|
||||
# Azure Service Management packages for Go
|
||||
|
||||
The `github.com/Azure/azure-sdk-for-go/management` packages are used to perform operations using the Azure Service Management (ASM), aka classic deployment model. Read more about [Azure Resource Manager vs. classic deployment](https://azure.microsoft.com/documentation/articles/resource-manager-deployment-model/). Packages for Azure Resource Manager are in the [arm](../arm) folder.
|
||||
|
||||
## First a Sidenote: Authentication and the Azure Service Manager
|
||||
|
||||
The client currently supports authentication to the Service Management
|
||||
API with certificates or Azure `.publishSettings` file. You can
|
||||
download the `.publishSettings` file for your subscriptions
|
||||
[here](https://manage.windowsazure.com/publishsettings).
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
package affinitygroup
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
const (
|
||||
azureCreateAffinityGroupURL = "/affinitygroups"
|
||||
azureGetAffinityGroupURL = "/affinitygroups/%s"
|
||||
azureListAffinityGroupsURL = "/affinitygroups"
|
||||
azureUpdateAffinityGroupURL = "/affinitygroups/%s"
|
||||
azureDeleteAffinityGroupURL = "/affinitygroups/%s"
|
||||
|
||||
errParameterNotSpecified = "Parameter %s not specified."
|
||||
)
|
||||
|
||||
// AffinityGroupClient simply contains a management.Client and has
|
||||
// methods for doing all affinity group-related API calls to Azure.
|
||||
type AffinityGroupClient struct {
|
||||
mgmtClient management.Client
|
||||
}
|
||||
|
||||
// NewClient returns an AffinityGroupClient with the given management.Client.
|
||||
func NewClient(mgmtClient management.Client) AffinityGroupClient {
|
||||
return AffinityGroupClient{mgmtClient}
|
||||
}
|
||||
|
||||
// CreateAffinityGroup creates a new affinity group.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/gg715317.aspx
|
||||
func (c AffinityGroupClient) CreateAffinityGroup(params CreateAffinityGroupParams) error {
|
||||
params.Label = encodeLabel(params.Label)
|
||||
|
||||
req, err := xml.Marshal(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = c.mgmtClient.SendAzurePostRequest(azureCreateAffinityGroupURL, req)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetAffinityGroup returns the system properties that are associated with the
|
||||
// specified affinity group.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/ee460789.aspx
|
||||
func (c AffinityGroupClient) GetAffinityGroup(name string) (AffinityGroup, error) {
|
||||
var affgroup AffinityGroup
|
||||
if name == "" {
|
||||
return affgroup, fmt.Errorf(errParameterNotSpecified, "name")
|
||||
}
|
||||
|
||||
url := fmt.Sprintf(azureGetAffinityGroupURL, name)
|
||||
resp, err := c.mgmtClient.SendAzureGetRequest(url)
|
||||
if err != nil {
|
||||
return affgroup, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(resp, &affgroup)
|
||||
affgroup.Label = decodeLabel(affgroup.Label)
|
||||
return affgroup, err
|
||||
}
|
||||
|
||||
// ListAffinityGroups lists the affinity groups off Azure.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/ee460797.aspx
|
||||
func (c AffinityGroupClient) ListAffinityGroups() (ListAffinityGroupsResponse, error) {
|
||||
var affinitygroups ListAffinityGroupsResponse
|
||||
|
||||
resp, err := c.mgmtClient.SendAzureGetRequest(azureListAffinityGroupsURL)
|
||||
if err != nil {
|
||||
return affinitygroups, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(resp, &affinitygroups)
|
||||
|
||||
for i, grp := range affinitygroups.AffinityGroups {
|
||||
affinitygroups.AffinityGroups[i].Label = decodeLabel(grp.Label)
|
||||
}
|
||||
|
||||
return affinitygroups, err
|
||||
}
|
||||
|
||||
// UpdateAffinityGroup updates the label or description for an the group.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/gg715316.aspx
|
||||
func (c AffinityGroupClient) UpdateAffinityGroup(name string, params UpdateAffinityGroupParams) error {
|
||||
if name == "" {
|
||||
return fmt.Errorf(errParameterNotSpecified, "name")
|
||||
}
|
||||
|
||||
params.Label = encodeLabel(params.Label)
|
||||
req, err := xml.Marshal(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
url := fmt.Sprintf(azureUpdateAffinityGroupURL, name)
|
||||
_, err = c.mgmtClient.SendAzurePutRequest(url, "text/xml", req)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteAffinityGroup deletes the given affinity group.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/gg715314.aspx
|
||||
func (c AffinityGroupClient) DeleteAffinityGroup(name string) error {
|
||||
if name == "" {
|
||||
return fmt.Errorf(errParameterNotSpecified, name)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf(azureDeleteAffinityGroupURL, name)
|
||||
_, err := c.mgmtClient.SendAzureDeleteRequest(url)
|
||||
return err
|
||||
}
|
||||
|
||||
// encodeLabel is a helper function which encodes the given string
|
||||
// to the base64 string which will be sent to Azure as a Label.
|
||||
func encodeLabel(label string) string {
|
||||
return base64.StdEncoding.EncodeToString([]byte(label))
|
||||
}
|
||||
|
||||
// decodeLabel is a helper function which decodes the base64 encoded
|
||||
// label received from Azure into standard encoding.
|
||||
func decodeLabel(label string) string {
|
||||
res, _ := base64.StdEncoding.DecodeString(label)
|
||||
return string(res)
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package affinitygroup
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
)
|
||||
|
||||
// CreateAffinityGroupParams respresents the set of parameters required for
|
||||
// creating an affinity group creation request to Azure.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/gg715317.aspx
|
||||
type CreateAffinityGroupParams struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure CreateAffinityGroup"`
|
||||
Name string
|
||||
Label string
|
||||
Description string `xml:",omitempty"`
|
||||
Location string
|
||||
}
|
||||
|
||||
// HostedService is a struct containing details about a hosted service that is
|
||||
// part of an affinity group on Azure.
|
||||
type HostedService struct {
|
||||
URL string `xml:"Url"`
|
||||
ServiceName string
|
||||
}
|
||||
|
||||
// StorageService is a struct containing details about a storage service that is
|
||||
// part of an affinity group on Azure.
|
||||
type StorageService struct {
|
||||
URL string `xml:"Url"`
|
||||
ServiceName string
|
||||
}
|
||||
|
||||
// AffinityGroup respresents the properties of an affinity group on Azure.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/ee460789.aspx
|
||||
type AffinityGroup struct {
|
||||
Name string
|
||||
Label string
|
||||
Description string
|
||||
Location string
|
||||
HostedServices []HostedService
|
||||
StorageServices []StorageService
|
||||
Capabilities []string
|
||||
}
|
||||
|
||||
// ComputeCapabilities represents the sets of capabilities of an affinity group
|
||||
// obtained from an affinity group list call to Azure.
|
||||
type ComputeCapabilities struct {
|
||||
VirtualMachineRoleSizes []string
|
||||
WebWorkerRoleSizes []string
|
||||
}
|
||||
|
||||
// AffinityGroupListResponse represents the properties obtained for each
|
||||
// affinity group listed off Azure.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/ee460797.aspx
|
||||
type AffinityGroupListResponse struct {
|
||||
Name string
|
||||
Label string
|
||||
Description string
|
||||
Location string
|
||||
Capabilities []string
|
||||
ComputeCapabilities ComputeCapabilities
|
||||
}
|
||||
|
||||
// ListAffinityGroupsResponse contains all the affinity groups obtained from a
|
||||
// call to the Azure API to list all affinity groups.
|
||||
type ListAffinityGroupsResponse struct {
|
||||
AffinityGroups []AffinityGroupListResponse `xml:"AffinityGroup"`
|
||||
}
|
||||
|
||||
// UpdateAffinityGroupParams if the set of parameters required to update an
|
||||
// affinity group on Azure.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/gg715316.aspx
|
||||
type UpdateAffinityGroupParams struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure UpdateAffinityGroup"`
|
||||
Label string `xml:",omitempty"`
|
||||
Description string `xml:",omitempty"`
|
||||
}
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
// Package management provides the main API client to construct other clients
|
||||
// and make requests to the Microsoft Azure Service Management REST API.
|
||||
package management
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultUserAgent = userAgent()
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultAzureManagementURL = "https://management.core.windows.net"
|
||||
DefaultOperationPollInterval = time.Second * 30
|
||||
DefaultAPIVersion = "2014-10-01"
|
||||
|
||||
errPublishSettingsConfiguration = "PublishSettingsFilePath is set. Consequently ManagementCertificatePath and SubscriptionId must not be set."
|
||||
errManagementCertificateConfiguration = "Both ManagementCertificatePath and SubscriptionId should be set, and PublishSettingsFilePath must not be set."
|
||||
errParamNotSpecified = "Parameter %s is not specified."
|
||||
)
|
||||
|
||||
type client struct {
|
||||
publishSettings publishSettings
|
||||
config ClientConfig
|
||||
}
|
||||
|
||||
// Client is the base Azure Service Management API client instance that
|
||||
// can be used to construct client instances for various services.
|
||||
type Client interface {
|
||||
// SendAzureGetRequest sends a request to the management API using the HTTP GET method
|
||||
// and returns the response body or an error.
|
||||
SendAzureGetRequest(url string) ([]byte, error)
|
||||
|
||||
// SendAzurePostRequest sends a request to the management API using the HTTP POST method
|
||||
// and returns the request ID or an error.
|
||||
SendAzurePostRequest(url string, data []byte) (OperationID, error)
|
||||
|
||||
// SendAzurePostRequestWithReturnedResponse sends a request to the management API using
|
||||
// the HTTP POST method and returns the response body or an error.
|
||||
SendAzurePostRequestWithReturnedResponse(url string, data []byte) ([]byte, error)
|
||||
|
||||
// SendAzurePutRequest sends a request to the management API using the HTTP PUT method
|
||||
// and returns the request ID or an error. The content type can be specified, however
|
||||
// if an empty string is passed, the default of "application/xml" will be used.
|
||||
SendAzurePutRequest(url, contentType string, data []byte) (OperationID, error)
|
||||
|
||||
// SendAzureDeleteRequest sends a request to the management API using the HTTP DELETE method
|
||||
// and returns the request ID or an error.
|
||||
SendAzureDeleteRequest(url string) (OperationID, error)
|
||||
|
||||
// GetOperationStatus gets the status of operation with given Operation ID.
|
||||
// WaitForOperation utility method can be used for polling for operation status.
|
||||
GetOperationStatus(operationID OperationID) (GetOperationStatusResponse, error)
|
||||
|
||||
// WaitForOperation polls the Azure API for given operation ID indefinitely
|
||||
// until the operation is completed with either success or failure.
|
||||
// It is meant to be used for waiting for the result of the methods that
|
||||
// return an OperationID value (meaning a long running operation has started).
|
||||
//
|
||||
// Cancellation of the polling loop (for instance, timing out) is done through
|
||||
// cancel channel. If the user does not want to cancel, a nil chan can be provided.
|
||||
// To cancel the method, it is recommended to close the channel provided to this
|
||||
// method.
|
||||
//
|
||||
// If the operation was not successful or cancelling is signaled, an error
|
||||
// is returned.
|
||||
WaitForOperation(operationID OperationID, cancel chan struct{}) error
|
||||
}
|
||||
|
||||
// ClientConfig provides a configuration for use by a Client.
|
||||
type ClientConfig struct {
|
||||
ManagementURL string
|
||||
OperationPollInterval time.Duration
|
||||
UserAgent string
|
||||
APIVersion string
|
||||
}
|
||||
|
||||
// NewAnonymousClient creates a new azure.Client with no credentials set.
|
||||
func NewAnonymousClient() Client {
|
||||
return client{}
|
||||
}
|
||||
|
||||
// DefaultConfig returns the default client configuration used to construct
|
||||
// a client. This value can be used to make modifications on the default API
|
||||
// configuration.
|
||||
func DefaultConfig() ClientConfig {
|
||||
return ClientConfig{
|
||||
ManagementURL: DefaultAzureManagementURL,
|
||||
OperationPollInterval: DefaultOperationPollInterval,
|
||||
APIVersion: DefaultAPIVersion,
|
||||
UserAgent: DefaultUserAgent,
|
||||
}
|
||||
}
|
||||
|
||||
// NewClient creates a new Client using the given subscription ID and
|
||||
// management certificate.
|
||||
func NewClient(subscriptionID string, managementCert []byte) (Client, error) {
|
||||
return NewClientFromConfig(subscriptionID, managementCert, DefaultConfig())
|
||||
}
|
||||
|
||||
// NewClientFromConfig creates a new Client using a given ClientConfig.
|
||||
func NewClientFromConfig(subscriptionID string, managementCert []byte, config ClientConfig) (Client, error) {
|
||||
return makeClient(subscriptionID, managementCert, config)
|
||||
}
|
||||
|
||||
func makeClient(subscriptionID string, managementCert []byte, config ClientConfig) (Client, error) {
|
||||
var c client
|
||||
|
||||
if subscriptionID == "" {
|
||||
return c, errors.New("azure: subscription ID required")
|
||||
}
|
||||
|
||||
if len(managementCert) == 0 {
|
||||
return c, errors.New("azure: management certificate required")
|
||||
}
|
||||
|
||||
publishSettings := publishSettings{
|
||||
SubscriptionID: subscriptionID,
|
||||
SubscriptionCert: managementCert,
|
||||
SubscriptionKey: managementCert,
|
||||
}
|
||||
|
||||
// Validate client configuration
|
||||
switch {
|
||||
case config.ManagementURL == "":
|
||||
return c, errors.New("azure: base URL required")
|
||||
case config.OperationPollInterval <= 0:
|
||||
return c, errors.New("azure: operation polling interval must be a positive duration")
|
||||
case config.APIVersion == "":
|
||||
return c, errors.New("azure: client configuration must specify an API version")
|
||||
case config.UserAgent == "":
|
||||
config.UserAgent = DefaultUserAgent
|
||||
}
|
||||
|
||||
return client{
|
||||
publishSettings: publishSettings,
|
||||
config: config,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func userAgent() string {
|
||||
return fmt.Sprintf("Go/%s (%s-%s) Azure-SDK-For-Go/%s asm/%s",
|
||||
runtime.Version(),
|
||||
runtime.GOARCH,
|
||||
runtime.GOOS,
|
||||
sdkVersion,
|
||||
DefaultAPIVersion)
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package management
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// AzureError represents an error returned by the management API. It has an error
|
||||
// code (for example, ResourceNotFound) and a descriptive message.
|
||||
type AzureError struct {
|
||||
Code string
|
||||
Message string
|
||||
}
|
||||
|
||||
//Error implements the error interface for the AzureError type.
|
||||
func (e AzureError) Error() string {
|
||||
return fmt.Sprintf("Error response from Azure. Code: %s, Message: %s", e.Code, e.Message)
|
||||
}
|
||||
|
||||
// IsResourceNotFoundError returns true if the provided error is an AzureError
|
||||
// reporting that a given resource has not been found.
|
||||
func IsResourceNotFoundError(err error) bool {
|
||||
azureErr, ok := err.(AzureError)
|
||||
return ok && azureErr.Code == "ResourceNotFound"
|
||||
}
|
||||
|
||||
// getAzureError converts an error response body into an AzureError instance.
|
||||
func getAzureError(responseBody []byte) error {
|
||||
var azErr AzureError
|
||||
err := xml.Unmarshal(responseBody, &azErr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed parsing contents to AzureError format: %v", err)
|
||||
}
|
||||
return azErr
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package management_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
// TestIsResourceNotFoundError tests IsResourceNotFoundError with the
|
||||
// set of given test cases.
|
||||
func TestIsResourceNotFoundError(t *testing.T) {
|
||||
// isResourceNotFoundTestCases is a set of structs comprising of the error
|
||||
// IsResourceNotFoundError should test and the expected result.
|
||||
var isResourceNotFoundTestCases = []struct {
|
||||
err error
|
||||
expected bool
|
||||
}{
|
||||
{nil, false},
|
||||
{fmt.Errorf("Some other random error."), false},
|
||||
{management.AzureError{Code: "ResourceNotFound"}, true},
|
||||
{management.AzureError{Code: "NotAResourceNotFound"}, false},
|
||||
}
|
||||
|
||||
for i, testCase := range isResourceNotFoundTestCases {
|
||||
if res := management.IsResourceNotFoundError(testCase.err); res != testCase.expected {
|
||||
t.Fatalf("Test %d: error %s - expected %t - got %t", i+1, testCase.err, testCase.expected, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
// Package hostedservice provides a client for Hosted Services.
|
||||
package hostedservice
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
const (
|
||||
azureXmlns = "http://schemas.microsoft.com/windowsazure"
|
||||
azureDeploymentListURL = "services/hostedservices/%s/deployments"
|
||||
azureHostedServiceListURL = "services/hostedservices"
|
||||
azureHostedServiceAvailabilityURL = "services/hostedservices/operations/isavailable/%s"
|
||||
azureDeploymentURL = "services/hostedservices/%s/deployments/%s"
|
||||
deleteAzureDeploymentURL = "services/hostedservices/%s/deployments/%s"
|
||||
getHostedServicePropertiesURL = "services/hostedservices/%s"
|
||||
azureServiceCertificateURL = "services/hostedservices/%s/certificates"
|
||||
|
||||
errParamNotSpecified = "Parameter %s is not specified."
|
||||
)
|
||||
|
||||
//NewClient is used to return a handle to the HostedService API
|
||||
func NewClient(client management.Client) HostedServiceClient {
|
||||
return HostedServiceClient{client: client}
|
||||
}
|
||||
|
||||
func (h HostedServiceClient) CreateHostedService(params CreateHostedServiceParameters) error {
|
||||
req, err := xml.Marshal(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = h.client.SendAzurePostRequest(azureHostedServiceListURL, req) // not a long running operation
|
||||
return err
|
||||
}
|
||||
|
||||
func (h HostedServiceClient) CheckHostedServiceNameAvailability(dnsName string) (AvailabilityResponse, error) {
|
||||
var r AvailabilityResponse
|
||||
if dnsName == "" {
|
||||
return r, fmt.Errorf(errParamNotSpecified, "dnsName")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(azureHostedServiceAvailabilityURL, dnsName)
|
||||
response, err := h.client.SendAzureGetRequest(requestURL)
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(response, &r)
|
||||
return r, err
|
||||
}
|
||||
|
||||
func (h HostedServiceClient) DeleteHostedService(dnsName string, deleteDisksAndBlobs bool) (management.OperationID, error) {
|
||||
if dnsName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "dnsName")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(getHostedServicePropertiesURL, dnsName)
|
||||
if deleteDisksAndBlobs {
|
||||
requestURL += "?comp=media"
|
||||
}
|
||||
return h.client.SendAzureDeleteRequest(requestURL)
|
||||
}
|
||||
|
||||
func (h HostedServiceClient) GetHostedService(name string) (HostedService, error) {
|
||||
hostedService := HostedService{}
|
||||
if name == "" {
|
||||
return hostedService, fmt.Errorf(errParamNotSpecified, "name")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(getHostedServicePropertiesURL, name)
|
||||
response, err := h.client.SendAzureGetRequest(requestURL)
|
||||
if err != nil {
|
||||
return hostedService, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(response, &hostedService)
|
||||
if err != nil {
|
||||
return hostedService, err
|
||||
}
|
||||
|
||||
decodedLabel, err := base64.StdEncoding.DecodeString(hostedService.LabelBase64)
|
||||
if err != nil {
|
||||
return hostedService, err
|
||||
}
|
||||
hostedService.Label = string(decodedLabel)
|
||||
return hostedService, nil
|
||||
}
|
||||
|
||||
func (h HostedServiceClient) ListHostedServices() (ListHostedServicesResponse, error) {
|
||||
var response ListHostedServicesResponse
|
||||
|
||||
data, err := h.client.SendAzureGetRequest(azureHostedServiceListURL)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(data, &response)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func (h HostedServiceClient) AddCertificate(dnsName string, certData []byte, certificateFormat CertificateFormat, password string) (management.OperationID, error) {
|
||||
if dnsName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "dnsName")
|
||||
}
|
||||
|
||||
certBase64 := base64.StdEncoding.EncodeToString(certData)
|
||||
|
||||
addCertificate := CertificateFile{
|
||||
Data: certBase64,
|
||||
CertificateFormat: certificateFormat,
|
||||
Password: password,
|
||||
Xmlns: azureXmlns,
|
||||
}
|
||||
buffer, err := xml.Marshal(addCertificate)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(azureServiceCertificateURL, dnsName)
|
||||
return h.client.SendAzurePostRequest(requestURL, buffer)
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package hostedservice
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
//HostedServiceClient is used to perform operations on Azure Hosted Services
|
||||
type HostedServiceClient struct {
|
||||
client management.Client
|
||||
}
|
||||
|
||||
type CreateHostedServiceParameters struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure CreateHostedService"`
|
||||
ServiceName string
|
||||
Label string
|
||||
Description string
|
||||
Location string
|
||||
ReverseDNSFqdn string `xml:"ReverseDnsFqdn,omitempty"`
|
||||
}
|
||||
|
||||
type AvailabilityResponse struct {
|
||||
Xmlns string `xml:"xmlns,attr"`
|
||||
Result bool
|
||||
Reason string
|
||||
}
|
||||
|
||||
type HostedService struct {
|
||||
URL string `xml:"Url"`
|
||||
ServiceName string
|
||||
Description string `xml:"HostedServiceProperties>Description"`
|
||||
AffinityGroup string `xml:"HostedServiceProperties>AffinityGroup"`
|
||||
Location string `xml:"HostedServiceProperties>Location"`
|
||||
LabelBase64 string `xml:"HostedServiceProperties>Label"`
|
||||
Label string
|
||||
Status string `xml:"HostedServiceProperties>Status"`
|
||||
ReverseDNSFqdn string `xml:"HostedServiceProperties>ReverseDnsFqdn"`
|
||||
DefaultWinRmCertificateThumbprint string
|
||||
}
|
||||
|
||||
type CertificateFile struct {
|
||||
Xmlns string `xml:"xmlns,attr"`
|
||||
Data string
|
||||
CertificateFormat CertificateFormat
|
||||
Password string `xml:",omitempty"`
|
||||
}
|
||||
|
||||
type CertificateFormat string
|
||||
|
||||
const (
|
||||
CertificateFormatPfx = CertificateFormat("pfx")
|
||||
CertificateFormatCer = CertificateFormat("cer")
|
||||
)
|
||||
|
||||
type ListHostedServicesResponse struct {
|
||||
HostedServices []HostedService `xml:"HostedService"`
|
||||
}
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
package management
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
msVersionHeader = "x-ms-version"
|
||||
requestIDHeader = "x-ms-request-id"
|
||||
uaHeader = "User-Agent"
|
||||
contentHeader = "Content-Type"
|
||||
defaultContentHeaderValue = "application/xml"
|
||||
)
|
||||
|
||||
func (client client) SendAzureGetRequest(url string) ([]byte, error) {
|
||||
resp, err := client.sendAzureRequest("GET", url, "", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return getResponseBody(resp)
|
||||
}
|
||||
|
||||
func (client client) SendAzurePostRequest(url string, data []byte) (OperationID, error) {
|
||||
return client.doAzureOperation("POST", url, "", data)
|
||||
}
|
||||
|
||||
func (client client) SendAzurePostRequestWithReturnedResponse(url string, data []byte) ([]byte, error) {
|
||||
resp, err := client.sendAzureRequest("POST", url, "", data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return getResponseBody(resp)
|
||||
}
|
||||
|
||||
func (client client) SendAzurePutRequest(url, contentType string, data []byte) (OperationID, error) {
|
||||
return client.doAzureOperation("PUT", url, contentType, data)
|
||||
}
|
||||
|
||||
func (client client) SendAzureDeleteRequest(url string) (OperationID, error) {
|
||||
return client.doAzureOperation("DELETE", url, "", nil)
|
||||
}
|
||||
|
||||
func (client client) doAzureOperation(method, url, contentType string, data []byte) (OperationID, error) {
|
||||
response, err := client.sendAzureRequest(method, url, contentType, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return getOperationID(response)
|
||||
}
|
||||
|
||||
func getOperationID(response *http.Response) (OperationID, error) {
|
||||
requestID := response.Header.Get(requestIDHeader)
|
||||
if requestID == "" {
|
||||
return "", fmt.Errorf("Could not retrieve operation id from %q header", requestIDHeader)
|
||||
}
|
||||
return OperationID(requestID), nil
|
||||
}
|
||||
|
||||
// sendAzureRequest constructs an HTTP client for the request, sends it to the
|
||||
// management API and returns the response or an error.
|
||||
func (client client) sendAzureRequest(method, url, contentType string, data []byte) (*http.Response, error) {
|
||||
if method == "" {
|
||||
return nil, fmt.Errorf(errParamNotSpecified, "method")
|
||||
}
|
||||
if url == "" {
|
||||
return nil, fmt.Errorf(errParamNotSpecified, "url")
|
||||
}
|
||||
|
||||
httpClient, err := client.createHTTPClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response, err := client.sendRequest(httpClient, url, method, contentType, data, 5)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// createHTTPClient creates an HTTP Client configured with the key pair for
|
||||
// the subscription for this client.
|
||||
func (client client) createHTTPClient() (*http.Client, error) {
|
||||
cert, err := tls.X509KeyPair(client.publishSettings.SubscriptionCert, client.publishSettings.SubscriptionKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
TLSClientConfig: &tls.Config{
|
||||
Renegotiation: tls.RenegotiateOnceAsClient,
|
||||
Certificates: []tls.Certificate{cert},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// sendRequest sends a request to the Azure management API using the given
|
||||
// HTTP client and parameters. It returns the response from the call or an
|
||||
// error.
|
||||
func (client client) sendRequest(httpClient *http.Client, url, requestType, contentType string, data []byte, numberOfRetries int) (*http.Response, error) {
|
||||
|
||||
absURI := client.createAzureRequestURI(url)
|
||||
|
||||
for {
|
||||
request, reqErr := client.createAzureRequest(absURI, requestType, contentType, data)
|
||||
if reqErr != nil {
|
||||
return nil, reqErr
|
||||
}
|
||||
|
||||
response, err := httpClient.Do(request)
|
||||
if err != nil {
|
||||
if numberOfRetries == 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client.sendRequest(httpClient, url, requestType, contentType, data, numberOfRetries-1)
|
||||
}
|
||||
if response.StatusCode == http.StatusTemporaryRedirect {
|
||||
// ASM's way of moving traffic around, see https://msdn.microsoft.com/en-us/library/azure/ee460801.aspx
|
||||
// Only handled automatically for GET/HEAD requests. This is for the rest of the http verbs.
|
||||
u, err := response.Location()
|
||||
if err != nil {
|
||||
return response, fmt.Errorf("Redirect requested but location header could not be retrieved: %v", err)
|
||||
}
|
||||
absURI = u.String()
|
||||
continue // re-issue request
|
||||
}
|
||||
|
||||
if response.StatusCode >= http.StatusBadRequest {
|
||||
body, err := getResponseBody(response)
|
||||
if err != nil {
|
||||
// Failed to read the response body
|
||||
return nil, err
|
||||
}
|
||||
azureErr := getAzureError(body)
|
||||
if azureErr != nil {
|
||||
if numberOfRetries == 0 {
|
||||
return nil, azureErr
|
||||
}
|
||||
|
||||
return client.sendRequest(httpClient, url, requestType, contentType, data, numberOfRetries-1)
|
||||
}
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
}
|
||||
|
||||
// createAzureRequestURI constructs the request uri using the management API endpoint and
|
||||
// subscription ID associated with the client.
|
||||
func (client client) createAzureRequestURI(url string) string {
|
||||
return fmt.Sprintf("%s/%s/%s", client.config.ManagementURL, client.publishSettings.SubscriptionID, url)
|
||||
}
|
||||
|
||||
// createAzureRequest packages up the request with the correct set of headers and returns
|
||||
// the request object or an error.
|
||||
func (client client) createAzureRequest(url string, requestType string, contentType string, data []byte) (*http.Request, error) {
|
||||
var request *http.Request
|
||||
var err error
|
||||
|
||||
if data != nil {
|
||||
body := bytes.NewBuffer(data)
|
||||
request, err = http.NewRequest(requestType, url, body)
|
||||
} else {
|
||||
request, err = http.NewRequest(requestType, url, nil)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
request.Header.Set(msVersionHeader, client.config.APIVersion)
|
||||
request.Header.Set(uaHeader, client.config.UserAgent)
|
||||
|
||||
if contentType != "" {
|
||||
request.Header.Set(contentHeader, contentType)
|
||||
} else {
|
||||
request.Header.Set(contentHeader, defaultContentHeaderValue)
|
||||
}
|
||||
|
||||
return request, nil
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// Package location provides a client for Locations.
|
||||
package location
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
const (
|
||||
azureLocationListURL = "locations"
|
||||
errParamNotSpecified = "Parameter %s is not specified."
|
||||
)
|
||||
|
||||
//NewClient is used to instantiate a new LocationClient from an Azure client
|
||||
func NewClient(client management.Client) LocationClient {
|
||||
return LocationClient{client: client}
|
||||
}
|
||||
|
||||
func (c LocationClient) ListLocations() (ListLocationsResponse, error) {
|
||||
var l ListLocationsResponse
|
||||
|
||||
response, err := c.client.SendAzureGetRequest(azureLocationListURL)
|
||||
if err != nil {
|
||||
return l, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(response, &l)
|
||||
return l, err
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package location
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
//LocationClient is used to perform operations on Azure Locations
|
||||
type LocationClient struct {
|
||||
client management.Client
|
||||
}
|
||||
|
||||
type ListLocationsResponse struct {
|
||||
XMLName xml.Name `xml:"Locations"`
|
||||
Locations []Location `xml:"Location"`
|
||||
}
|
||||
|
||||
type Location struct {
|
||||
Name string
|
||||
DisplayName string
|
||||
AvailableServices []string `xml:"AvailableServices>AvailableService"`
|
||||
WebWorkerRoleSizes []string `xml:"ComputeCapabilities>WebWorkerRoleSizes>RoleSize"`
|
||||
VirtualMachineRoleSizes []string `xml:"ComputeCapabilities>VirtualMachinesRoleSizes>RoleSize"`
|
||||
}
|
||||
|
||||
func (ll ListLocationsResponse) String() string {
|
||||
var buf bytes.Buffer
|
||||
for _, l := range ll.Locations {
|
||||
fmt.Fprintf(&buf, "%s, ", l.Name)
|
||||
}
|
||||
|
||||
return strings.Trim(buf.String(), ", ")
|
||||
}
|
||||
Generated
Vendored
+245
@@ -0,0 +1,245 @@
|
||||
// Package networksecuritygroup provides a client for Network Security Groups.
|
||||
package networksecuritygroup
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
const (
|
||||
createSecurityGroupURL = "services/networking/networksecuritygroups"
|
||||
deleteSecurityGroupURL = "services/networking/networksecuritygroups/%s"
|
||||
getSecurityGroupURL = "services/networking/networksecuritygroups/%s?detaillevel=full"
|
||||
listSecurityGroupsURL = "services/networking/networksecuritygroups"
|
||||
addSecurityGroupToSubnetURL = "services/networking/virtualnetwork/%s/subnets/%s/networksecuritygroups"
|
||||
getSecurityGroupForSubnetURL = "services/networking/virtualnetwork/%s/subnets/%s/networksecuritygroups"
|
||||
removeSecurityGroupFromSubnetURL = "services/networking/virtualnetwork/%s/subnets/%s/networksecuritygroups/%s"
|
||||
setSecurityGroupRuleURL = "services/networking/networksecuritygroups/%s/rules/%s"
|
||||
deleteSecurityGroupRuleURL = "services/networking/networksecuritygroups/%s/rules/%s"
|
||||
|
||||
errParamNotSpecified = "Parameter %s is not specified."
|
||||
)
|
||||
|
||||
// NewClient is used to instantiate a new SecurityGroupClient from an Azure client
|
||||
func NewClient(client management.Client) SecurityGroupClient {
|
||||
return SecurityGroupClient{client: client}
|
||||
}
|
||||
|
||||
// CreateNetworkSecurityGroup creates a new network security group within
|
||||
// the context of the specified subscription
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn913818.aspx
|
||||
func (sg SecurityGroupClient) CreateNetworkSecurityGroup(
|
||||
name string,
|
||||
label string,
|
||||
location string) (management.OperationID, error) {
|
||||
if name == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "name")
|
||||
}
|
||||
if location == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "location")
|
||||
}
|
||||
|
||||
data, err := xml.Marshal(SecurityGroupRequest{
|
||||
Name: name,
|
||||
Label: label,
|
||||
Location: location,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(createSecurityGroupURL)
|
||||
return sg.client.SendAzurePostRequest(requestURL, data)
|
||||
}
|
||||
|
||||
// DeleteNetworkSecurityGroup deletes the specified network security group from the subscription
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn913825.aspx
|
||||
func (sg SecurityGroupClient) DeleteNetworkSecurityGroup(
|
||||
name string) (management.OperationID, error) {
|
||||
if name == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "name")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(deleteSecurityGroupURL, name)
|
||||
return sg.client.SendAzureDeleteRequest(requestURL)
|
||||
}
|
||||
|
||||
// GetNetworkSecurityGroup returns information about the specified network security group
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn913821.aspx
|
||||
func (sg SecurityGroupClient) GetNetworkSecurityGroup(name string) (SecurityGroupResponse, error) {
|
||||
if name == "" {
|
||||
return SecurityGroupResponse{}, fmt.Errorf(errParamNotSpecified, "name")
|
||||
}
|
||||
|
||||
var securityGroup SecurityGroupResponse
|
||||
|
||||
requestURL := fmt.Sprintf(getSecurityGroupURL, name)
|
||||
response, err := sg.client.SendAzureGetRequest(requestURL)
|
||||
if err != nil {
|
||||
return securityGroup, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(response, &securityGroup)
|
||||
return securityGroup, err
|
||||
}
|
||||
|
||||
// ListNetworkSecurityGroups returns a list of the network security groups
|
||||
// in the specified subscription
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn913815.aspx
|
||||
func (sg SecurityGroupClient) ListNetworkSecurityGroups() (SecurityGroupList, error) {
|
||||
var securityGroups SecurityGroupList
|
||||
|
||||
response, err := sg.client.SendAzureGetRequest(listSecurityGroupsURL)
|
||||
if err != nil {
|
||||
return securityGroups, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(response, &securityGroups)
|
||||
return securityGroups, err
|
||||
}
|
||||
|
||||
// AddNetworkSecurityToSubnet associates the network security group with
|
||||
// specified subnet in a virtual network
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn913822.aspx
|
||||
func (sg SecurityGroupClient) AddNetworkSecurityToSubnet(
|
||||
name string,
|
||||
subnet string,
|
||||
virtualNetwork string) (management.OperationID, error) {
|
||||
if name == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "name")
|
||||
}
|
||||
if subnet == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "subnet")
|
||||
}
|
||||
if virtualNetwork == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "virtualNetwork")
|
||||
}
|
||||
|
||||
data, err := xml.Marshal(SecurityGroupRequest{Name: name})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(addSecurityGroupToSubnetURL, virtualNetwork, subnet)
|
||||
return sg.client.SendAzurePostRequest(requestURL, data)
|
||||
}
|
||||
|
||||
// GetNetworkSecurityGroupForSubnet returns information about the network
|
||||
// security group associated with a subnet
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn913817.aspx
|
||||
func (sg SecurityGroupClient) GetNetworkSecurityGroupForSubnet(
|
||||
subnet string,
|
||||
virtualNetwork string) (SecurityGroupResponse, error) {
|
||||
if subnet == "" {
|
||||
return SecurityGroupResponse{}, fmt.Errorf(errParamNotSpecified, "subnet")
|
||||
}
|
||||
if virtualNetwork == "" {
|
||||
return SecurityGroupResponse{}, fmt.Errorf(errParamNotSpecified, "virtualNetwork")
|
||||
}
|
||||
|
||||
var securityGroup SecurityGroupResponse
|
||||
|
||||
requestURL := fmt.Sprintf(getSecurityGroupForSubnetURL, virtualNetwork, subnet)
|
||||
response, err := sg.client.SendAzureGetRequest(requestURL)
|
||||
if err != nil {
|
||||
return securityGroup, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(response, &securityGroup)
|
||||
return securityGroup, err
|
||||
}
|
||||
|
||||
// RemoveNetworkSecurityGroupFromSubnet removes the association of the
|
||||
// specified network security group from the specified subnet
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn913820.aspx
|
||||
func (sg SecurityGroupClient) RemoveNetworkSecurityGroupFromSubnet(
|
||||
name string,
|
||||
subnet string,
|
||||
virtualNetwork string) (management.OperationID, error) {
|
||||
if name == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "name")
|
||||
}
|
||||
if subnet == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "subnet")
|
||||
}
|
||||
if virtualNetwork == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "virtualNetwork")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(removeSecurityGroupFromSubnetURL, virtualNetwork, subnet, name)
|
||||
return sg.client.SendAzureDeleteRequest(requestURL)
|
||||
}
|
||||
|
||||
// SetNetworkSecurityGroupRule adds or updates a network security rule that
|
||||
// is associated with the specified network security group
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn913819.aspx
|
||||
func (sg SecurityGroupClient) SetNetworkSecurityGroupRule(
|
||||
securityGroup string,
|
||||
rule RuleRequest) (management.OperationID, error) {
|
||||
if securityGroup == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "securityGroup")
|
||||
}
|
||||
if rule.Name == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "Name")
|
||||
}
|
||||
if rule.Type == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "Type")
|
||||
}
|
||||
if rule.Priority == 0 {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "Priority")
|
||||
}
|
||||
if rule.Action == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "Action")
|
||||
}
|
||||
if rule.SourceAddressPrefix == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "SourceAddressPrefix")
|
||||
}
|
||||
if rule.SourcePortRange == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "SourcePortRange")
|
||||
}
|
||||
if rule.DestinationAddressPrefix == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "DestinationAddressPrefix")
|
||||
}
|
||||
if rule.DestinationPortRange == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "DestinationPortRange")
|
||||
}
|
||||
if rule.Protocol == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "Protocol")
|
||||
}
|
||||
|
||||
data, err := xml.Marshal(rule)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(setSecurityGroupRuleURL, securityGroup, rule.Name)
|
||||
return sg.client.SendAzurePutRequest(requestURL, "", data)
|
||||
}
|
||||
|
||||
// DeleteNetworkSecurityGroupRule deletes a network security group rule from
|
||||
// the specified network security group
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn913816.aspx
|
||||
func (sg SecurityGroupClient) DeleteNetworkSecurityGroupRule(
|
||||
securityGroup string,
|
||||
rule string) (management.OperationID, error) {
|
||||
if securityGroup == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "securityGroup")
|
||||
}
|
||||
if rule == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "rule")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(deleteSecurityGroupRuleURL, securityGroup, rule)
|
||||
return sg.client.SendAzureDeleteRequest(requestURL)
|
||||
}
|
||||
Generated
Vendored
+115
@@ -0,0 +1,115 @@
|
||||
// Package networksecuritygroup implements operations for managing network security groups
|
||||
// using the Service Management REST API
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn913824.aspx
|
||||
package networksecuritygroup
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
// SecurityGroupClient is used to perform operations on network security groups
|
||||
type SecurityGroupClient struct {
|
||||
client management.Client
|
||||
}
|
||||
|
||||
// SecurityGroupRequest represents a network security group
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn913821.aspx
|
||||
type SecurityGroupRequest struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure NetworkSecurityGroup"`
|
||||
Name string
|
||||
Label string `xml:",omitempty"`
|
||||
Location string `xml:",omitempty"`
|
||||
}
|
||||
|
||||
// SecurityGroupResponse represents a network security group
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn913821.aspx
|
||||
type SecurityGroupResponse struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure NetworkSecurityGroup"`
|
||||
Name string
|
||||
Label string `xml:",omitempty"`
|
||||
Location string `xml:",omitempty"`
|
||||
State SecurityGroupState `xml:",omitempty"`
|
||||
Rules []RuleResponse `xml:">Rule,omitempty"`
|
||||
}
|
||||
|
||||
// SecurityGroupList represents a list of security groups
|
||||
type SecurityGroupList []SecurityGroupResponse
|
||||
|
||||
// SecurityGroupState represents a security group state
|
||||
type SecurityGroupState string
|
||||
|
||||
// These constants represent the possible security group states
|
||||
const (
|
||||
SecurityGroupStateCreated SecurityGroupState = "Created"
|
||||
SecurityGroupStateCreating SecurityGroupState = "Creating"
|
||||
SecurityGroupStateUpdating SecurityGroupState = "Updating"
|
||||
SecurityGroupStateDeleting SecurityGroupState = "Deleting"
|
||||
SecurityGroupStateUnavailable SecurityGroupState = "Unavailable"
|
||||
)
|
||||
|
||||
// RuleRequest represents a single rule of a network security group
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn913821.aspx#bk_rules
|
||||
type RuleRequest struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure Rule"`
|
||||
Name string
|
||||
Type RuleType
|
||||
Priority int
|
||||
Action RuleAction
|
||||
SourceAddressPrefix string
|
||||
SourcePortRange string
|
||||
DestinationAddressPrefix string
|
||||
DestinationPortRange string
|
||||
Protocol RuleProtocol
|
||||
}
|
||||
|
||||
// RuleResponse represents a single rule of a network security group
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn913821.aspx#bk_rules
|
||||
type RuleResponse struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure Rule"`
|
||||
Name string
|
||||
Type RuleType
|
||||
Priority int
|
||||
Action RuleAction
|
||||
SourceAddressPrefix string
|
||||
SourcePortRange string
|
||||
DestinationAddressPrefix string
|
||||
DestinationPortRange string
|
||||
Protocol RuleProtocol
|
||||
State string `xml:",omitempty"`
|
||||
IsDefault bool `xml:",omitempty"`
|
||||
}
|
||||
|
||||
// RuleType represents a rule type
|
||||
type RuleType string
|
||||
|
||||
// These constants represent the possible rule types
|
||||
const (
|
||||
RuleTypeInbound RuleType = "Inbound"
|
||||
RuleTypeOutbound RuleType = "Outbound"
|
||||
)
|
||||
|
||||
// RuleAction represents a rule action
|
||||
type RuleAction string
|
||||
|
||||
// These constants represent the possible rule actions
|
||||
const (
|
||||
RuleActionAllow RuleAction = "Allow"
|
||||
RuleActionDeny RuleAction = "Deny"
|
||||
)
|
||||
|
||||
// RuleProtocol represents a rule protocol
|
||||
type RuleProtocol string
|
||||
|
||||
// These constants represent the possible rule types
|
||||
const (
|
||||
RuleProtocolTCP RuleProtocol = "TCP"
|
||||
RuleProtocolUDP RuleProtocol = "UDP"
|
||||
RuleProtocolAll RuleProtocol = "*"
|
||||
)
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package management
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrOperationCancelled from WaitForOperation when the polling loop is
|
||||
// cancelled through signaling the channel.
|
||||
ErrOperationCancelled = errors.New("Polling for operation status cancelled")
|
||||
)
|
||||
|
||||
// GetOperationStatusResponse represents an in-flight operation. Use
|
||||
// client.GetOperationStatus() to get the operation given the operation ID, or
|
||||
// use WaitForOperation() to poll and wait until the operation has completed.
|
||||
// See https://msdn.microsoft.com/en-us/library/azure/ee460783.aspx
|
||||
type GetOperationStatusResponse struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure Operation"`
|
||||
ID string
|
||||
Status OperationStatus
|
||||
HTTPStatusCode string
|
||||
Error *AzureError
|
||||
}
|
||||
|
||||
// OperationStatus describes the states an Microsoft Azure Service Management
|
||||
// operation an be in.
|
||||
type OperationStatus string
|
||||
|
||||
// List of states an operation can be reported as
|
||||
const (
|
||||
OperationStatusInProgress OperationStatus = "InProgress"
|
||||
OperationStatusSucceeded OperationStatus = "Succeeded"
|
||||
OperationStatusFailed OperationStatus = "Failed"
|
||||
)
|
||||
|
||||
// OperationID is assigned by Azure API and can be used to look up the status of
|
||||
// an operation
|
||||
type OperationID string
|
||||
|
||||
func (c client) GetOperationStatus(operationID OperationID) (GetOperationStatusResponse, error) {
|
||||
operation := GetOperationStatusResponse{}
|
||||
if operationID == "" {
|
||||
return operation, fmt.Errorf(errParamNotSpecified, "operationID")
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("operations/%s", operationID)
|
||||
response, azureErr := c.SendAzureGetRequest(url)
|
||||
if azureErr != nil {
|
||||
return operation, azureErr
|
||||
}
|
||||
|
||||
err := xml.Unmarshal(response, &operation)
|
||||
return operation, err
|
||||
}
|
||||
|
||||
func (c client) WaitForOperation(operationID OperationID, cancel chan struct{}) error {
|
||||
for {
|
||||
done, err := c.checkOperationStatus(operationID)
|
||||
if err != nil || done {
|
||||
return err
|
||||
}
|
||||
select {
|
||||
case <-time.After(c.config.OperationPollInterval):
|
||||
case <-cancel:
|
||||
return ErrOperationCancelled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c client) checkOperationStatus(id OperationID) (done bool, err error) {
|
||||
op, err := c.GetOperationStatus(id)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Failed to get operation status '%s': %v", id, err)
|
||||
}
|
||||
|
||||
switch op.Status {
|
||||
case OperationStatusSucceeded:
|
||||
return true, nil
|
||||
case OperationStatusFailed:
|
||||
if op.Error != nil {
|
||||
return true, op.Error
|
||||
}
|
||||
return true, fmt.Errorf("Azure Operation (x-ms-request-id=%s) has failed", id)
|
||||
case OperationStatusInProgress:
|
||||
return false, nil
|
||||
default:
|
||||
return false, fmt.Errorf("Unknown operation status returned from API: %s (x-ms-request-id=%s)", op.Status, id)
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
// Package osimage provides a client for Operating System Images.
|
||||
package osimage
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
const (
|
||||
azureImageListURL = "services/images"
|
||||
errInvalidImage = "Can not find image %s in specified subscription, please specify another image name."
|
||||
errParamNotSpecified = "Parameter %s is not specified."
|
||||
)
|
||||
|
||||
// NewClient is used to instantiate a new OSImageClient from an Azure client.
|
||||
func NewClient(client management.Client) OSImageClient {
|
||||
return OSImageClient{client: client}
|
||||
}
|
||||
|
||||
func (c OSImageClient) ListOSImages() (ListOSImagesResponse, error) {
|
||||
var l ListOSImagesResponse
|
||||
|
||||
response, err := c.client.SendAzureGetRequest(azureImageListURL)
|
||||
if err != nil {
|
||||
return l, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(response, &l)
|
||||
return l, err
|
||||
}
|
||||
|
||||
// AddOSImage adds an operating system image to the image repository that is associated with the specified subscription.
|
||||
//
|
||||
// See https://msdn.microsoft.com/en-us/library/azure/jj157192.aspx for details.
|
||||
func (c OSImageClient) AddOSImage(osi *OSImage) (management.OperationID, error) {
|
||||
data, err := xml.Marshal(osi)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return c.client.SendAzurePostRequest(azureImageListURL, data)
|
||||
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package osimage
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
// OSImageClient is used to perform operations on Azure Locations
|
||||
type OSImageClient struct {
|
||||
client management.Client
|
||||
}
|
||||
|
||||
type ListOSImagesResponse struct {
|
||||
XMLName xml.Name `xml:"Images"`
|
||||
OSImages []OSImage `xml:"OSImage"`
|
||||
}
|
||||
|
||||
type OSImage struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure OSImage"`
|
||||
Category string // Public || Private || MSDN
|
||||
Label string // Specifies an identifier for the image.
|
||||
LogicalSizeInGB float64 //Specifies the size, in GB, of the image.
|
||||
Name string // Specifies the name of the operating system image. This is the name that is used when creating one or more virtual machines using the image.
|
||||
OS string // Linux || Windows
|
||||
Eula string // Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA.
|
||||
Description string // Specifies the description of the image.
|
||||
Location string // The geo-location in which this media is located. The Location value is derived from storage account that contains the blob in which the media is located. If the storage account belongs to an affinity group the value is NULL.
|
||||
AffinityGroup string // Specifies the affinity in which the media is located. The AffinityGroup value is derived from storage account that contains the blob in which the media is located. If the storage account does not belong to an affinity group the value is NULL and the element is not displayed in the response. This value is NULL for platform images.
|
||||
MediaLink string // Specifies the location of the vhd file for the image. The storage account where the vhd is located must be associated with the specified subscription.
|
||||
ImageFamily string // Specifies a value that can be used to group images.
|
||||
PublishedDate string // Specifies the date when the image was added to the image repository.
|
||||
IsPremium string // Indicates whether the image contains software or associated services that will incur charges above the core price for the virtual machine. For additional details, see the PricingDetailLink element.
|
||||
PrivacyURI string `xml:"PrivacyUri"` // Specifies the URI that points to a document that contains the privacy policy related to the image.
|
||||
RecommendedVMSize string // Specifies the size to use for the virtual machine that is created from the image.
|
||||
PublisherName string // The name of the publisher of the image. All user images have a publisher name of User.
|
||||
PricingDetailLink string // Specifies a URL for an image with IsPremium set to true, which contains the pricing details for a virtual machine that is created from the image.
|
||||
IconURI string `xml:"IconUri"` // Specifies the Uri to the icon that is displayed for the image in the Management Portal.
|
||||
SmallIconURI string `xml:"SmallIconUri"` // Specifies the URI to the small icon that is displayed when the image is presented in the Microsoft Azure Management Portal.
|
||||
Language string // Specifies the language of the image.
|
||||
IOType IOType // Provisioned || Standard
|
||||
}
|
||||
|
||||
type IOType string
|
||||
|
||||
const (
|
||||
IOTypeProvisioned IOType = "Provisioned"
|
||||
IOTypeStandard IOType = "Standard"
|
||||
)
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
package management
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"golang.org/x/crypto/pkcs12"
|
||||
)
|
||||
|
||||
// ClientFromPublishSettingsData unmarshalls the contents of a publish settings file
|
||||
// from https://manage.windowsazure.com/publishsettings.
|
||||
// If subscriptionID is left empty, the first subscription in the file is used.
|
||||
func ClientFromPublishSettingsData(settingsData []byte, subscriptionID string) (client Client, err error) {
|
||||
return ClientFromPublishSettingsDataWithConfig(settingsData, subscriptionID, DefaultConfig())
|
||||
}
|
||||
|
||||
// ClientFromPublishSettingsFile reads a publish settings file downloaded from https://manage.windowsazure.com/publishsettings.
|
||||
// If subscriptionID is left empty, the first subscription in the file is used.
|
||||
func ClientFromPublishSettingsFile(filePath, subscriptionID string) (client Client, err error) {
|
||||
return ClientFromPublishSettingsFileWithConfig(filePath, subscriptionID, DefaultConfig())
|
||||
}
|
||||
|
||||
// ClientFromPublishSettingsFileWithConfig reads a publish settings file downloaded from https://manage.windowsazure.com/publishsettings.
|
||||
// If subscriptionID is left empty, the first subscription in the file is used.
|
||||
func ClientFromPublishSettingsFileWithConfig(filePath, subscriptionID string, config ClientConfig) (client Client, err error) {
|
||||
if filePath == "" {
|
||||
return client, fmt.Errorf(errParamNotSpecified, "filePath")
|
||||
}
|
||||
|
||||
publishSettingsContent, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return client, err
|
||||
}
|
||||
|
||||
return ClientFromPublishSettingsDataWithConfig(publishSettingsContent, subscriptionID, config)
|
||||
}
|
||||
|
||||
// ClientFromPublishSettingsDataWithConfig unmarshalls the contents of a publish settings file
|
||||
// from https://manage.windowsazure.com/publishsettings.
|
||||
// If subscriptionID is left empty, the first subscription in the string is used.
|
||||
func ClientFromPublishSettingsDataWithConfig(data []byte, subscriptionID string, config ClientConfig) (client Client, err error) {
|
||||
publishData := publishData{}
|
||||
if err = xml.Unmarshal(data, &publishData); err != nil {
|
||||
return client, err
|
||||
}
|
||||
|
||||
for _, profile := range publishData.PublishProfiles {
|
||||
for _, sub := range profile.Subscriptions {
|
||||
if sub.ID == subscriptionID || subscriptionID == "" {
|
||||
base64Cert := sub.ManagementCertificate
|
||||
if base64Cert == "" {
|
||||
base64Cert = profile.ManagementCertificate
|
||||
}
|
||||
|
||||
pfxData, err := base64.StdEncoding.DecodeString(base64Cert)
|
||||
if err != nil {
|
||||
return client, err
|
||||
}
|
||||
|
||||
pems, err := pkcs12.ToPEM(pfxData, "")
|
||||
if err != nil {
|
||||
return client, err
|
||||
}
|
||||
|
||||
cert := []byte{}
|
||||
for _, b := range pems {
|
||||
cert = append(cert, pem.EncodeToMemory(b)...)
|
||||
}
|
||||
|
||||
config.ManagementURL = sub.ServiceManagementURL
|
||||
return makeClient(sub.ID, cert, config)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return client, fmt.Errorf("could not find subscription '%s' in settings provided", subscriptionID)
|
||||
}
|
||||
|
||||
type publishSettings struct {
|
||||
SubscriptionID string
|
||||
SubscriptionCert []byte
|
||||
SubscriptionKey []byte
|
||||
}
|
||||
|
||||
type publishData struct {
|
||||
XMLName xml.Name `xml:"PublishData"`
|
||||
PublishProfiles []publishProfile `xml:"PublishProfile"`
|
||||
}
|
||||
|
||||
type publishProfile struct {
|
||||
XMLName xml.Name `xml:"PublishProfile"`
|
||||
SchemaVersion string `xml:",attr"`
|
||||
PublishMethod string `xml:",attr"`
|
||||
URL string `xml:"Url,attr"`
|
||||
ManagementCertificate string `xml:",attr"`
|
||||
Subscriptions []subscription `xml:"Subscription"`
|
||||
}
|
||||
|
||||
type subscription struct {
|
||||
XMLName xml.Name `xml:"Subscription"`
|
||||
ServiceManagementURL string `xml:"ServiceManagementUrl,attr"`
|
||||
ID string `xml:"Id,attr"`
|
||||
Name string `xml:",attr"`
|
||||
ManagementCertificate string `xml:",attr"`
|
||||
}
|
||||
+316
@@ -0,0 +1,316 @@
|
||||
package sql
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
// Definitions of numerous constants representing API endpoints.
|
||||
const (
|
||||
azureCreateDatabaseServerURL = "services/sqlservers/servers"
|
||||
azureListDatabaseServersURL = "services/sqlservers/servers"
|
||||
azureDeleteDatabaseServerURL = "services/sqlservers/servers/%s"
|
||||
|
||||
azureCreateFirewallRuleURL = "services/sqlservers/servers/%s/firewallrules"
|
||||
azureGetFirewallRuleURL = "services/sqlservers/servers/%s/firewallrules/%s"
|
||||
azureListFirewallRulesURL = "services/sqlservers/servers/%s/firewallrules"
|
||||
azureUpdateFirewallRuleURL = "services/sqlservers/servers/%s/firewallrules/%s"
|
||||
azureDeleteFirewallRuleURL = "services/sqlservers/servers/%s/firewallrules/%s"
|
||||
|
||||
azureCreateDatabaseURL = "services/sqlservers/servers/%s/databases"
|
||||
azureGetDatabaseURL = "services/sqlservers/servers/%s/databases/%s"
|
||||
azureListDatabasesURL = "services/sqlservers/servers/%s/databases?contentview=generic"
|
||||
azureUpdateDatabaseURL = "services/sqlservers/servers/%s/databases/%s"
|
||||
azureDeleteDatabaseURL = "services/sqlservers/servers/%s/databases/%s"
|
||||
|
||||
errParamNotSpecified = "Parameter %s was not specified."
|
||||
|
||||
DatabaseStateCreating = "Creating"
|
||||
)
|
||||
|
||||
// SQLDatabaseClient defines various database CRUD operations.
|
||||
// It contains a management.Client for making the actual http calls.
|
||||
type SQLDatabaseClient struct {
|
||||
mgmtClient management.Client
|
||||
}
|
||||
|
||||
// NewClient returns a new SQLDatabaseClient struct with the provided
|
||||
// management.Client as the underlying client.
|
||||
func NewClient(mgmtClient management.Client) SQLDatabaseClient {
|
||||
return SQLDatabaseClient{mgmtClient}
|
||||
}
|
||||
|
||||
// CreateServer creates a new Azure SQL Database server and return its name.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505699.aspx
|
||||
func (c SQLDatabaseClient) CreateServer(params DatabaseServerCreateParams) (string, error) {
|
||||
req, err := xml.Marshal(params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resp, err := c.mgmtClient.SendAzurePostRequestWithReturnedResponse(azureCreateDatabaseServerURL, req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var name string
|
||||
err = xml.Unmarshal(resp, &name)
|
||||
|
||||
return name, err
|
||||
}
|
||||
|
||||
// ListServers retrieves the Azure SQL Database servers for this subscription.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505702.aspx
|
||||
func (c SQLDatabaseClient) ListServers() (ListServersResponse, error) {
|
||||
var resp ListServersResponse
|
||||
|
||||
data, err := c.mgmtClient.SendAzureGetRequest(azureListDatabaseServersURL)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(data, &resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// DeleteServer deletes an Azure SQL Database server (including all its databases).
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505695.aspx
|
||||
func (c SQLDatabaseClient) DeleteServer(name string) error {
|
||||
if name == "" {
|
||||
return fmt.Errorf(errParamNotSpecified, "name")
|
||||
}
|
||||
|
||||
url := fmt.Sprintf(azureDeleteDatabaseServerURL, name)
|
||||
_, err := c.mgmtClient.SendAzureDeleteRequest(url)
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateFirewallRule creates an Azure SQL Database server
|
||||
// firewall rule.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505712.aspx
|
||||
func (c SQLDatabaseClient) CreateFirewallRule(server string, params FirewallRuleCreateParams) error {
|
||||
if server == "" {
|
||||
return fmt.Errorf(errParamNotSpecified, "server")
|
||||
}
|
||||
|
||||
req, err := xml.Marshal(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
url := fmt.Sprintf(azureCreateFirewallRuleURL, server)
|
||||
|
||||
_, err = c.mgmtClient.SendAzurePostRequest(url, req)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetFirewallRule gets the details of an Azure SQL Database Server firewall rule.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505698.aspx
|
||||
func (c SQLDatabaseClient) GetFirewallRule(server, ruleName string) (FirewallRuleResponse, error) {
|
||||
var rule FirewallRuleResponse
|
||||
|
||||
if server == "" {
|
||||
return rule, fmt.Errorf(errParamNotSpecified, "server")
|
||||
}
|
||||
if ruleName == "" {
|
||||
return rule, fmt.Errorf(errParamNotSpecified, "ruleName")
|
||||
}
|
||||
|
||||
url := fmt.Sprintf(azureGetFirewallRuleURL, server, ruleName)
|
||||
resp, err := c.mgmtClient.SendAzureGetRequest(url)
|
||||
if err != nil {
|
||||
return rule, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(resp, &rule)
|
||||
return rule, err
|
||||
}
|
||||
|
||||
// ListFirewallRules retrieves the set of firewall rules for an Azure SQL
|
||||
// Database Server.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505715.aspx
|
||||
func (c SQLDatabaseClient) ListFirewallRules(server string) (ListFirewallRulesResponse, error) {
|
||||
var rules ListFirewallRulesResponse
|
||||
|
||||
if server == "" {
|
||||
return rules, fmt.Errorf(errParamNotSpecified, "server")
|
||||
}
|
||||
|
||||
url := fmt.Sprintf(azureListFirewallRulesURL, server)
|
||||
resp, err := c.mgmtClient.SendAzureGetRequest(url)
|
||||
if err != nil {
|
||||
return rules, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(resp, &rules)
|
||||
return rules, err
|
||||
}
|
||||
|
||||
// UpdateFirewallRule update a firewall rule for an Azure SQL Database server.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505707.aspx
|
||||
func (c SQLDatabaseClient) UpdateFirewallRule(server, ruleName string, params FirewallRuleUpdateParams) error {
|
||||
if server == "" {
|
||||
return fmt.Errorf(errParamNotSpecified, "server")
|
||||
}
|
||||
if ruleName == "" {
|
||||
return fmt.Errorf(errParamNotSpecified, "ruleName")
|
||||
}
|
||||
|
||||
req, err := xml.Marshal(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
url := fmt.Sprintf(azureUpdateFirewallRuleURL, server, ruleName)
|
||||
_, err = c.mgmtClient.SendAzurePutRequest(url, "text/xml", req)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteFirewallRule deletes an Azure SQL Database server firewall rule.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505706.aspx
|
||||
func (c SQLDatabaseClient) DeleteFirewallRule(server, ruleName string) error {
|
||||
if server == "" {
|
||||
return fmt.Errorf(errParamNotSpecified, "server")
|
||||
}
|
||||
if ruleName == "" {
|
||||
return fmt.Errorf(errParamNotSpecified, "ruleName")
|
||||
}
|
||||
|
||||
url := fmt.Sprintf(azureDeleteFirewallRuleURL, server, ruleName)
|
||||
|
||||
_, err := c.mgmtClient.SendAzureDeleteRequest(url)
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateDatabase creates a new Microsoft Azure SQL Database on the given database server.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505701.aspx
|
||||
func (c SQLDatabaseClient) CreateDatabase(server string, params DatabaseCreateParams) error {
|
||||
if server == "" {
|
||||
return fmt.Errorf(errParamNotSpecified, "server")
|
||||
}
|
||||
|
||||
req, err := xml.Marshal(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
target := fmt.Sprintf(azureCreateDatabaseURL, server)
|
||||
_, err = c.mgmtClient.SendAzurePostRequest(target, req)
|
||||
return err
|
||||
}
|
||||
|
||||
// WaitForDatabaseCreation is a helper method which waits
|
||||
// for the creation of the database on the given server.
|
||||
func (c SQLDatabaseClient) WaitForDatabaseCreation(
|
||||
server, database string,
|
||||
cancel chan struct{}) error {
|
||||
for {
|
||||
stat, err := c.GetDatabase(server, database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if stat.State != DatabaseStateCreating {
|
||||
return nil
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(management.DefaultOperationPollInterval):
|
||||
case <-cancel:
|
||||
return management.ErrOperationCancelled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetDatabase gets the details for an Azure SQL Database.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505708.aspx
|
||||
func (c SQLDatabaseClient) GetDatabase(server, database string) (ServiceResource, error) {
|
||||
var db ServiceResource
|
||||
|
||||
if database == "" {
|
||||
return db, fmt.Errorf(errParamNotSpecified, "database")
|
||||
}
|
||||
if server == "" {
|
||||
return db, fmt.Errorf(errParamNotSpecified, "server")
|
||||
}
|
||||
|
||||
url := fmt.Sprintf(azureGetDatabaseURL, server, database)
|
||||
resp, err := c.mgmtClient.SendAzureGetRequest(url)
|
||||
if err != nil {
|
||||
return db, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(resp, &db)
|
||||
return db, err
|
||||
}
|
||||
|
||||
// ListDatabases returns a list of Azure SQL Databases on the given server.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505711.aspx
|
||||
func (c SQLDatabaseClient) ListDatabases(server string) (ListDatabasesResponse, error) {
|
||||
var databases ListDatabasesResponse
|
||||
if server == "" {
|
||||
return databases, fmt.Errorf(errParamNotSpecified, "server name")
|
||||
}
|
||||
|
||||
url := fmt.Sprintf(azureListDatabasesURL, server)
|
||||
resp, err := c.mgmtClient.SendAzureGetRequest(url)
|
||||
if err != nil {
|
||||
return databases, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(resp, &databases)
|
||||
return databases, err
|
||||
}
|
||||
|
||||
// UpdateDatabase updates the details of the given Database off the given server.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505718.aspx
|
||||
func (c SQLDatabaseClient) UpdateDatabase(
|
||||
server, database string,
|
||||
params ServiceResourceUpdateParams) (management.OperationID, error) {
|
||||
if database == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "database")
|
||||
}
|
||||
if server == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "server")
|
||||
}
|
||||
|
||||
url := fmt.Sprintf(azureUpdateDatabaseURL, server, database)
|
||||
req, err := xml.Marshal(params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return c.mgmtClient.SendAzurePutRequest(url, "text/xml", req)
|
||||
}
|
||||
|
||||
// DeleteDatabase deletes the Azure SQL Database off the given server.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505705.aspx
|
||||
func (c SQLDatabaseClient) DeleteDatabase(server, database string) error {
|
||||
if database == "" {
|
||||
return fmt.Errorf(errParamNotSpecified, "database")
|
||||
}
|
||||
if server == "" {
|
||||
return fmt.Errorf(errParamNotSpecified, "server")
|
||||
}
|
||||
|
||||
url := fmt.Sprintf(azureDeleteDatabaseURL, server, database)
|
||||
|
||||
_, err := c.mgmtClient.SendAzureDeleteRequest(url)
|
||||
|
||||
return err
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
package sql
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
)
|
||||
|
||||
// DatabaseServerCreateParams represents the set of possible parameters
|
||||
// when issuing a database server creation request to Azure.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505699.aspx
|
||||
type DatabaseServerCreateParams struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/sqlazure/2010/12/ Server"`
|
||||
AdministratorLogin string
|
||||
AdministratorLoginPassword string
|
||||
Location string
|
||||
Version string
|
||||
}
|
||||
|
||||
// DatabaseServerCreateResponse represents the response following the creation of
|
||||
// a database server on Azure.
|
||||
type DatabaseServerCreateResponse struct {
|
||||
ServerName string
|
||||
}
|
||||
|
||||
const (
|
||||
DatabaseServerVersion11 = "2.0"
|
||||
DatabaseServerVersion12 = "12.0"
|
||||
)
|
||||
|
||||
// DatabaseServer represents the set of data received from
|
||||
// a database server list operation.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505702.aspx
|
||||
type DatabaseServer struct {
|
||||
Name string
|
||||
AdministratorLogin string
|
||||
Location string
|
||||
FullyQualifiedDomainName string
|
||||
Version string
|
||||
State string
|
||||
}
|
||||
|
||||
type ListServersResponse struct {
|
||||
DatabaseServers []DatabaseServer `xml:"Server"`
|
||||
}
|
||||
|
||||
// FirewallRuleCreateParams represents the set of possible
|
||||
// parameters when creating a firewall rule on an Azure database server.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505712.aspx
|
||||
type FirewallRuleCreateParams struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure ServiceResource"`
|
||||
Name string
|
||||
StartIPAddress string
|
||||
EndIPAddress string
|
||||
}
|
||||
|
||||
// FirewallRuleResponse represents the set of data received from
|
||||
// an Azure database server firewall rule get response.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505698.aspx
|
||||
type FirewallRuleResponse struct {
|
||||
Name string
|
||||
StartIPAddress string
|
||||
EndIPAddress string
|
||||
}
|
||||
|
||||
type ListFirewallRulesResponse struct {
|
||||
FirewallRules []FirewallRuleResponse `xml:"ServiceResource"`
|
||||
}
|
||||
|
||||
// FirewallRuleUpdateParams represents the set of possible
|
||||
// parameters when issuing an update of a database server firewall rule.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505707.aspx
|
||||
type FirewallRuleUpdateParams struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure ServiceResource"`
|
||||
Name string
|
||||
StartIPAddress string
|
||||
EndIPAddress string
|
||||
}
|
||||
|
||||
// DatabaseCreateParams represents the set of possible parameters when issuing
|
||||
// a database creation to Azure, and reading a list response from Azure.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505701.aspx
|
||||
type DatabaseCreateParams struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure ServiceResource"`
|
||||
Name string
|
||||
Edition string `xml:",omitempty"`
|
||||
CollationName string `xml:",omitempty"`
|
||||
MaxSizeBytes int64 `xml:",omitempty"`
|
||||
ServiceObjectiveID string `xml:"ServiceObjectiveId,omitempty"`
|
||||
}
|
||||
|
||||
// ServiceResource represents the set of parameters obtained from a database
|
||||
// get or list call.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505708.aspx
|
||||
type ServiceResource struct {
|
||||
Name string
|
||||
State string
|
||||
SelfLink string
|
||||
Edition string
|
||||
CollationName string
|
||||
MaxSizeBytes int64
|
||||
ServiceObjectiveID string `xml:"ServiceObjectiveId,omitempty"`
|
||||
}
|
||||
|
||||
type ListDatabasesResponse struct {
|
||||
ServiceResources []ServiceResource `xml:"ServiceResource"`
|
||||
}
|
||||
|
||||
// ServiceResourceUpdateParams represents the set of parameters available
|
||||
// for a database service update operation.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn505718.aspx
|
||||
type ServiceResourceUpdateParams struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure ServiceResource"`
|
||||
Name string
|
||||
Edition string `xml:",omitempty"`
|
||||
MaxSizeBytes int64 `xml:",omitempty"`
|
||||
ServiceObjectiveID string `xml:"ServiceObjectiveId,omitempty"`
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
// Package storageservice provides a client for Storage Services.
|
||||
package storageservice
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
const (
|
||||
azureStorageServiceListURL = "services/storageservices"
|
||||
azureStorageServiceURL = "services/storageservices/%s"
|
||||
azureStorageServiceKeysURL = "services/storageservices/%s/keys"
|
||||
azureStorageAccountAvailabilityURL = "services/storageservices/operations/isavailable/%s"
|
||||
|
||||
azureXmlns = "http://schemas.microsoft.com/windowsazure"
|
||||
|
||||
errParamNotSpecified = "Parameter %s is not specified."
|
||||
)
|
||||
|
||||
// NewClient is used to instantiate a new StorageServiceClient from an Azure
|
||||
// client.
|
||||
func NewClient(s management.Client) StorageServiceClient {
|
||||
return StorageServiceClient{client: s}
|
||||
}
|
||||
|
||||
func (s StorageServiceClient) ListStorageServices() (ListStorageServicesResponse, error) {
|
||||
var l ListStorageServicesResponse
|
||||
response, err := s.client.SendAzureGetRequest(azureStorageServiceListURL)
|
||||
if err != nil {
|
||||
return l, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(response, &l)
|
||||
return l, err
|
||||
}
|
||||
|
||||
func (s StorageServiceClient) GetStorageService(serviceName string) (StorageServiceResponse, error) {
|
||||
var svc StorageServiceResponse
|
||||
if serviceName == "" {
|
||||
return svc, fmt.Errorf(errParamNotSpecified, "serviceName")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(azureStorageServiceURL, serviceName)
|
||||
response, err := s.client.SendAzureGetRequest(requestURL)
|
||||
if err != nil {
|
||||
return svc, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(response, &svc)
|
||||
return svc, err
|
||||
}
|
||||
|
||||
func (s StorageServiceClient) GetStorageServiceKeys(serviceName string) (GetStorageServiceKeysResponse, error) {
|
||||
var r GetStorageServiceKeysResponse
|
||||
if serviceName == "" {
|
||||
return r, fmt.Errorf(errParamNotSpecified, "serviceName")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(azureStorageServiceKeysURL, serviceName)
|
||||
data, err := s.client.SendAzureGetRequest(requestURL)
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(data, &r)
|
||||
return r, err
|
||||
}
|
||||
|
||||
func (s StorageServiceClient) CreateStorageService(parameters StorageAccountCreateParameters) (management.OperationID, error) {
|
||||
data, err := xml.Marshal(CreateStorageServiceInput{
|
||||
StorageAccountCreateParameters: parameters})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return s.client.SendAzurePostRequest(azureStorageServiceListURL, data)
|
||||
}
|
||||
|
||||
func (s StorageServiceClient) DeleteStorageService(serviceName string) (management.OperationID, error) {
|
||||
if serviceName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "serviceName")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(azureStorageServiceURL, serviceName)
|
||||
return s.client.SendAzureDeleteRequest(requestURL)
|
||||
}
|
||||
|
||||
// CheckStorageAccountNameAvailability checks to if the specified storage account
|
||||
// name is available.
|
||||
//
|
||||
// See https://msdn.microsoft.com/en-us/library/azure/jj154125.aspx
|
||||
func (s StorageServiceClient) CheckStorageAccountNameAvailability(name string) (AvailabilityResponse, error) {
|
||||
var r AvailabilityResponse
|
||||
if name == "" {
|
||||
return r, fmt.Errorf(errParamNotSpecified, "name")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(azureStorageAccountAvailabilityURL, name)
|
||||
response, err := s.client.SendAzureGetRequest(requestURL)
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(response, &r)
|
||||
return r, err
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package storageservice
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
// StorageServiceClient is used to perform operations on Azure Storage
|
||||
type StorageServiceClient struct {
|
||||
client management.Client
|
||||
}
|
||||
|
||||
type ListStorageServicesResponse struct {
|
||||
StorageServices []StorageServiceResponse `xml:"StorageService"`
|
||||
}
|
||||
|
||||
type StorageServiceResponse struct {
|
||||
URL string `xml:"Url"`
|
||||
ServiceName string
|
||||
StorageServiceProperties StorageServiceProperties
|
||||
}
|
||||
|
||||
type StorageServiceProperties struct {
|
||||
Description string
|
||||
Location string
|
||||
Label string
|
||||
Status string
|
||||
Endpoints []string `xml:"Endpoints>Endpoint"`
|
||||
GeoReplicationEnabled string
|
||||
GeoPrimaryRegion string
|
||||
}
|
||||
|
||||
type GetStorageServiceKeysResponse struct {
|
||||
URL string `xml:"Url"`
|
||||
PrimaryKey string `xml:"StorageServiceKeys>Primary"`
|
||||
SecondaryKey string `xml:"StorageServiceKeys>Secondary"`
|
||||
}
|
||||
|
||||
type CreateStorageServiceInput struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure CreateStorageServiceInput"`
|
||||
StorageAccountCreateParameters
|
||||
}
|
||||
|
||||
type StorageAccountCreateParameters struct {
|
||||
ServiceName string
|
||||
Description string `xml:",omitempty"`
|
||||
Label string
|
||||
AffinityGroup string `xml:",omitempty"`
|
||||
Location string `xml:",omitempty"`
|
||||
ExtendedProperties ExtendedPropertyList
|
||||
AccountType AccountType
|
||||
}
|
||||
|
||||
type AccountType string
|
||||
|
||||
const (
|
||||
AccountTypeStandardLRS AccountType = "Standard_LRS"
|
||||
AccountTypeStandardZRS AccountType = "Standard_ZRS"
|
||||
AccountTypeStandardGRS AccountType = "Standard_GRS"
|
||||
AccountTypeStandardRAGRS AccountType = "Standard_RAGRS"
|
||||
AccountTypePremiumLRS AccountType = "Premium_LRS"
|
||||
)
|
||||
|
||||
type ExtendedPropertyList struct {
|
||||
ExtendedProperty []ExtendedProperty
|
||||
}
|
||||
|
||||
type ExtendedProperty struct {
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
type AvailabilityResponse struct {
|
||||
XMLName xml.Name `xml:"AvailabilityResponse"`
|
||||
Xmlns string `xml:"xmlns,attr"`
|
||||
Result bool
|
||||
Reason string
|
||||
}
|
||||
Generated
Vendored
+31
@@ -0,0 +1,31 @@
|
||||
package storageservice
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_StorageServiceKeysResponse_Unmarshal(t *testing.T) {
|
||||
// from https://msdn.microsoft.com/en-us/library/azure/ee460785.aspx
|
||||
response := []byte(`<?xml version="1.0" encoding="utf-8"?>
|
||||
<StorageService xmlns="http://schemas.microsoft.com/windowsazure">
|
||||
<Url>storage-service-url</Url>
|
||||
<StorageServiceKeys>
|
||||
<Primary>primary-key</Primary>
|
||||
<Secondary>secondary-key</Secondary>
|
||||
</StorageServiceKeys>
|
||||
</StorageService>`)
|
||||
|
||||
keysResponse := GetStorageServiceKeysResponse{}
|
||||
err := xml.Unmarshal(response, &keysResponse)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if expected := "primary-key"; keysResponse.PrimaryKey != expected {
|
||||
t.Fatalf("Expected %q but got %q", expected, keysResponse.PrimaryKey)
|
||||
}
|
||||
if expected := "secondary-key"; keysResponse.SecondaryKey != expected {
|
||||
t.Fatalf("Expected %q but got %q", expected, keysResponse.SecondaryKey)
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+87
@@ -0,0 +1,87 @@
|
||||
// Package testutils contains some test utilities for the Azure SDK
|
||||
package testutils
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
// GetTestClient returns a management Client for testing. Expects
|
||||
// AZSUBSCRIPTIONID and AZCERTDATA to be present in the environment. AZCERTDATA
|
||||
// is the base64encoded binary representation of the PEM certificate data.
|
||||
func GetTestClient(t *testing.T) management.Client {
|
||||
subid := os.Getenv("AZSUBSCRIPTIONID")
|
||||
certdata := os.Getenv("AZCERTDATA")
|
||||
if subid == "" || certdata == "" {
|
||||
t.Skip("AZSUBSCRIPTIONID or AZCERTDATA not set, skipping test")
|
||||
}
|
||||
cert, err := base64.StdEncoding.DecodeString(certdata)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
client, err := management.NewClient(subid, cert)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return testClient{client, t}
|
||||
}
|
||||
|
||||
type testClient struct {
|
||||
management.Client
|
||||
t *testing.T
|
||||
}
|
||||
|
||||
func chop(d []byte) string {
|
||||
const maxlen = 5000
|
||||
|
||||
s := string(d)
|
||||
|
||||
if len(s) > maxlen {
|
||||
return s[:maxlen] + "..."
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (l testClient) SendAzureGetRequest(url string) ([]byte, error) {
|
||||
d, err := l.Client.SendAzureGetRequest(url)
|
||||
logOperation(l.t, "GET", url, nil, d, "", err)
|
||||
return d, err
|
||||
}
|
||||
|
||||
func (l testClient) SendAzurePostRequest(url string, data []byte) (management.OperationID, error) {
|
||||
oid, err := l.Client.SendAzurePostRequest(url, data)
|
||||
logOperation(l.t, "POST", url, data, nil, oid, err)
|
||||
return oid, err
|
||||
}
|
||||
|
||||
func (l testClient) SendAzurePutRequest(url string, contentType string, data []byte) (management.OperationID, error) {
|
||||
oid, err := l.Client.SendAzurePutRequest(url, contentType, data)
|
||||
logOperation(l.t, "PUT", url, data, nil, oid, err)
|
||||
return oid, err
|
||||
}
|
||||
|
||||
func (l testClient) SendAzureDeleteRequest(url string) (management.OperationID, error) {
|
||||
oid, err := l.Client.SendAzureDeleteRequest(url)
|
||||
logOperation(l.t, "DELETE", url, nil, nil, oid, err)
|
||||
return oid, err
|
||||
}
|
||||
|
||||
func logOperation(t *testing.T, method, url string, requestData, responseData []byte, oid management.OperationID, err error) {
|
||||
t.Logf("AZURE> %s %s\n", method, url)
|
||||
if requestData != nil {
|
||||
t.Logf(" >>> %s\n", chop(requestData))
|
||||
}
|
||||
if err != nil {
|
||||
t.Logf(" <<< ERROR: %+v\n", err)
|
||||
} else {
|
||||
if responseData != nil {
|
||||
t.Logf(" <<< %s\n", chop(responseData))
|
||||
} else {
|
||||
t.Logf(" <<< OperationID: %s\n", oid)
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package management
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func getResponseBody(response *http.Response) ([]byte, error) {
|
||||
defer response.Body.Close()
|
||||
return ioutil.ReadAll(response.Body)
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package management
|
||||
|
||||
var (
|
||||
sdkVersion = "v10.1.0-beta"
|
||||
)
|
||||
+328
@@ -0,0 +1,328 @@
|
||||
// Package virtualmachine provides a client for Virtual Machines.
|
||||
package virtualmachine
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
const (
|
||||
azureDeploymentListURL = "services/hostedservices/%s/deployments"
|
||||
azureDeploymentURL = "services/hostedservices/%s/deployments/%s"
|
||||
azureListDeploymentsInSlotURL = "services/hostedservices/%s/deploymentslots/Production"
|
||||
deleteAzureDeploymentURL = "services/hostedservices/%s/deployments/%s?comp=media"
|
||||
azureAddRoleURL = "services/hostedservices/%s/deployments/%s/roles"
|
||||
azureRoleURL = "services/hostedservices/%s/deployments/%s/roles/%s"
|
||||
azureOperationsURL = "services/hostedservices/%s/deployments/%s/roleinstances/%s/Operations"
|
||||
azureRoleSizeListURL = "rolesizes"
|
||||
|
||||
errParamNotSpecified = "Parameter %s is not specified."
|
||||
)
|
||||
|
||||
//NewClient is used to instantiate a new VirtualMachineClient from an Azure client
|
||||
func NewClient(client management.Client) VirtualMachineClient {
|
||||
return VirtualMachineClient{client: client}
|
||||
}
|
||||
|
||||
// CreateDeploymentOptions can be used to create a customized deployement request
|
||||
type CreateDeploymentOptions struct {
|
||||
DNSServers []DNSServer
|
||||
LoadBalancers []LoadBalancer
|
||||
ReservedIPName string
|
||||
VirtualNetworkName string
|
||||
}
|
||||
|
||||
// CreateDeployment creates a deployment and then creates a virtual machine
|
||||
// in the deployment based on the specified configuration.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/jj157194.aspx
|
||||
func (vm VirtualMachineClient) CreateDeployment(
|
||||
role Role,
|
||||
cloudServiceName string,
|
||||
options CreateDeploymentOptions) (management.OperationID, error) {
|
||||
|
||||
req := DeploymentRequest{
|
||||
Name: role.RoleName,
|
||||
DeploymentSlot: "Production",
|
||||
Label: role.RoleName,
|
||||
RoleList: []Role{role},
|
||||
DNSServers: options.DNSServers,
|
||||
LoadBalancers: options.LoadBalancers,
|
||||
ReservedIPName: options.ReservedIPName,
|
||||
VirtualNetworkName: options.VirtualNetworkName,
|
||||
}
|
||||
|
||||
data, err := xml.Marshal(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(azureDeploymentListURL, cloudServiceName)
|
||||
return vm.client.SendAzurePostRequest(requestURL, data)
|
||||
}
|
||||
|
||||
// GetDeploymentName queries an existing Azure cloud service for the name of the Deployment,
|
||||
// if any, in its 'Production' slot (the only slot possible). If none exists, it returns empty
|
||||
// string but no error
|
||||
//
|
||||
//https://msdn.microsoft.com/en-us/library/azure/ee460804.aspx
|
||||
func (vm VirtualMachineClient) GetDeploymentName(cloudServiceName string) (string, error) {
|
||||
var deployment DeploymentResponse
|
||||
if cloudServiceName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
|
||||
}
|
||||
requestURL := fmt.Sprintf(azureListDeploymentsInSlotURL, cloudServiceName)
|
||||
response, err := vm.client.SendAzureGetRequest(requestURL)
|
||||
if err != nil {
|
||||
if management.IsResourceNotFoundError(err) {
|
||||
return "", nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
err = xml.Unmarshal(response, &deployment)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return deployment.Name, nil
|
||||
}
|
||||
|
||||
func (vm VirtualMachineClient) GetDeployment(cloudServiceName, deploymentName string) (DeploymentResponse, error) {
|
||||
var deployment DeploymentResponse
|
||||
if cloudServiceName == "" {
|
||||
return deployment, fmt.Errorf(errParamNotSpecified, "cloudServiceName")
|
||||
}
|
||||
if deploymentName == "" {
|
||||
return deployment, fmt.Errorf(errParamNotSpecified, "deploymentName")
|
||||
}
|
||||
requestURL := fmt.Sprintf(azureDeploymentURL, cloudServiceName, deploymentName)
|
||||
response, azureErr := vm.client.SendAzureGetRequest(requestURL)
|
||||
if azureErr != nil {
|
||||
return deployment, azureErr
|
||||
}
|
||||
|
||||
err := xml.Unmarshal(response, &deployment)
|
||||
return deployment, err
|
||||
}
|
||||
|
||||
func (vm VirtualMachineClient) DeleteDeployment(cloudServiceName, deploymentName string) (management.OperationID, error) {
|
||||
if cloudServiceName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
|
||||
}
|
||||
if deploymentName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(deleteAzureDeploymentURL, cloudServiceName, deploymentName)
|
||||
return vm.client.SendAzureDeleteRequest(requestURL)
|
||||
}
|
||||
|
||||
func (vm VirtualMachineClient) GetRole(cloudServiceName, deploymentName, roleName string) (*Role, error) {
|
||||
if cloudServiceName == "" {
|
||||
return nil, fmt.Errorf(errParamNotSpecified, "cloudServiceName")
|
||||
}
|
||||
if deploymentName == "" {
|
||||
return nil, fmt.Errorf(errParamNotSpecified, "deploymentName")
|
||||
}
|
||||
if roleName == "" {
|
||||
return nil, fmt.Errorf(errParamNotSpecified, "roleName")
|
||||
}
|
||||
|
||||
role := new(Role)
|
||||
|
||||
requestURL := fmt.Sprintf(azureRoleURL, cloudServiceName, deploymentName, roleName)
|
||||
response, azureErr := vm.client.SendAzureGetRequest(requestURL)
|
||||
if azureErr != nil {
|
||||
return nil, azureErr
|
||||
}
|
||||
|
||||
err := xml.Unmarshal(response, role)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return role, nil
|
||||
}
|
||||
|
||||
// AddRole adds a Virtual Machine to a deployment of Virtual Machines, where role name = VM name
|
||||
// See https://msdn.microsoft.com/en-us/library/azure/jj157186.aspx
|
||||
func (vm VirtualMachineClient) AddRole(cloudServiceName string, deploymentName string, role Role) (management.OperationID, error) {
|
||||
if cloudServiceName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
|
||||
}
|
||||
if deploymentName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
|
||||
}
|
||||
|
||||
data, err := xml.Marshal(PersistentVMRole{Role: role})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(azureAddRoleURL, cloudServiceName, deploymentName)
|
||||
return vm.client.SendAzurePostRequest(requestURL, data)
|
||||
}
|
||||
|
||||
// UpdateRole updates the configuration of the specified virtual machine
|
||||
// See https://msdn.microsoft.com/en-us/library/azure/jj157187.aspx
|
||||
func (vm VirtualMachineClient) UpdateRole(cloudServiceName, deploymentName, roleName string, role Role) (management.OperationID, error) {
|
||||
if cloudServiceName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
|
||||
}
|
||||
if deploymentName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
|
||||
}
|
||||
if roleName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "roleName")
|
||||
}
|
||||
|
||||
data, err := xml.Marshal(PersistentVMRole{Role: role})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(azureRoleURL, cloudServiceName, deploymentName, roleName)
|
||||
return vm.client.SendAzurePutRequest(requestURL, "text/xml", data)
|
||||
}
|
||||
|
||||
func (vm VirtualMachineClient) StartRole(cloudServiceName, deploymentName, roleName string) (management.OperationID, error) {
|
||||
if cloudServiceName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
|
||||
}
|
||||
if deploymentName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
|
||||
}
|
||||
if roleName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "roleName")
|
||||
}
|
||||
|
||||
startRoleOperationBytes, err := xml.Marshal(StartRoleOperation{
|
||||
OperationType: "StartRoleOperation",
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(azureOperationsURL, cloudServiceName, deploymentName, roleName)
|
||||
return vm.client.SendAzurePostRequest(requestURL, startRoleOperationBytes)
|
||||
}
|
||||
|
||||
func (vm VirtualMachineClient) ShutdownRole(cloudServiceName, deploymentName, roleName string, postaction PostShutdownAction) (management.OperationID, error) {
|
||||
if cloudServiceName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
|
||||
}
|
||||
if deploymentName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
|
||||
}
|
||||
if roleName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "roleName")
|
||||
}
|
||||
|
||||
shutdownRoleOperationBytes, err := xml.Marshal(ShutdownRoleOperation{
|
||||
OperationType: "ShutdownRoleOperation",
|
||||
PostShutdownAction: postaction,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(azureOperationsURL, cloudServiceName, deploymentName, roleName)
|
||||
return vm.client.SendAzurePostRequest(requestURL, shutdownRoleOperationBytes)
|
||||
}
|
||||
|
||||
func (vm VirtualMachineClient) RestartRole(cloudServiceName, deploymentName, roleName string) (management.OperationID, error) {
|
||||
if cloudServiceName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
|
||||
}
|
||||
if deploymentName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
|
||||
}
|
||||
if roleName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "roleName")
|
||||
}
|
||||
|
||||
restartRoleOperationBytes, err := xml.Marshal(RestartRoleOperation{
|
||||
OperationType: "RestartRoleOperation",
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(azureOperationsURL, cloudServiceName, deploymentName, roleName)
|
||||
return vm.client.SendAzurePostRequest(requestURL, restartRoleOperationBytes)
|
||||
}
|
||||
|
||||
func (vm VirtualMachineClient) DeleteRole(cloudServiceName, deploymentName, roleName string, deleteVHD bool) (management.OperationID, error) {
|
||||
if cloudServiceName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
|
||||
}
|
||||
if deploymentName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
|
||||
}
|
||||
if roleName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "roleName")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(azureRoleURL, cloudServiceName, deploymentName, roleName)
|
||||
if deleteVHD {
|
||||
requestURL += "?comp=media"
|
||||
}
|
||||
return vm.client.SendAzureDeleteRequest(requestURL)
|
||||
}
|
||||
|
||||
func (vm VirtualMachineClient) GetRoleSizeList() (RoleSizeList, error) {
|
||||
roleSizeList := RoleSizeList{}
|
||||
|
||||
response, err := vm.client.SendAzureGetRequest(azureRoleSizeListURL)
|
||||
if err != nil {
|
||||
return roleSizeList, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(response, &roleSizeList)
|
||||
return roleSizeList, err
|
||||
}
|
||||
|
||||
// CaptureRole captures a VM role. If reprovisioningConfigurationSet is non-nil,
|
||||
// the VM role is redeployed after capturing the image, otherwise, the original
|
||||
// VM role is deleted.
|
||||
//
|
||||
// NOTE: an image resulting from this operation shows up in
|
||||
// osimage.GetImageList() as images with Category "User".
|
||||
func (vm VirtualMachineClient) CaptureRole(cloudServiceName, deploymentName, roleName, imageName, imageLabel string,
|
||||
reprovisioningConfigurationSet *ConfigurationSet) (management.OperationID, error) {
|
||||
if cloudServiceName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
|
||||
}
|
||||
if deploymentName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
|
||||
}
|
||||
if roleName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "roleName")
|
||||
}
|
||||
|
||||
if reprovisioningConfigurationSet != nil &&
|
||||
!(reprovisioningConfigurationSet.ConfigurationSetType == ConfigurationSetTypeLinuxProvisioning ||
|
||||
reprovisioningConfigurationSet.ConfigurationSetType == ConfigurationSetTypeWindowsProvisioning) {
|
||||
return "", fmt.Errorf("ConfigurationSet type can only be WindowsProvisioningConfiguration or LinuxProvisioningConfiguration")
|
||||
}
|
||||
|
||||
operation := CaptureRoleOperation{
|
||||
OperationType: "CaptureRoleOperation",
|
||||
PostCaptureAction: PostCaptureActionReprovision,
|
||||
ProvisioningConfiguration: reprovisioningConfigurationSet,
|
||||
TargetImageLabel: imageLabel,
|
||||
TargetImageName: imageName,
|
||||
}
|
||||
if reprovisioningConfigurationSet == nil {
|
||||
operation.PostCaptureAction = PostCaptureActionDelete
|
||||
}
|
||||
|
||||
data, err := xml.Marshal(operation)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return vm.client.SendAzurePostRequest(fmt.Sprintf(azureOperationsURL, cloudServiceName, deploymentName, roleName), data)
|
||||
}
|
||||
+579
@@ -0,0 +1,579 @@
|
||||
package virtualmachine
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
vmdisk "github.com/Azure/azure-sdk-for-go/management/virtualmachinedisk"
|
||||
)
|
||||
|
||||
// VirtualMachineClient is used to perform operations on Azure Virtual Machines
|
||||
type VirtualMachineClient struct {
|
||||
client management.Client
|
||||
}
|
||||
|
||||
// DeploymentRequest is the type for creating a deployment and Virtual Machine
|
||||
// in the deployment based on the specified configuration. See
|
||||
// https://msdn.microsoft.com/en-us/library/azure/jj157194.aspx
|
||||
type DeploymentRequest struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure Deployment"`
|
||||
// Required parameters:
|
||||
Name string `` // Specifies a name for the deployment. The deployment name must be unique among other deployments for the cloud service.
|
||||
DeploymentSlot string `` // Specifies the environment in which the Virtual Machine is to be deployed. The only allowable value is Production.
|
||||
Label string `` // Specifies an identifier for the deployment. The label can be up to 100 characters long. The label can be used for tracking purposes.
|
||||
RoleList []Role `xml:">Role"` // Contains information about the Virtual Machines that are to be deployed.
|
||||
// Optional parameters:
|
||||
VirtualNetworkName string `xml:",omitempty"` // Specifies the name of an existing virtual network to which the deployment will belong.
|
||||
DNSServers []DNSServer `xml:"Dns>DnsServers>DnsServer,omitempty"` // Contains a list of DNS servers to associate with the Virtual Machine.
|
||||
LoadBalancers []LoadBalancer `xml:">LoadBalancer,omitempty"` // Contains a list of internal load balancers that can be assigned to input endpoints.
|
||||
ReservedIPName string `xml:",omitempty"` // Specifies the name of a reserved IP address that is to be assigned to the deployment.
|
||||
}
|
||||
|
||||
// DeploymentResponse is the type for receiving deployment information
|
||||
// See https://msdn.microsoft.com/en-us/library/azure/ee460804.aspx
|
||||
type DeploymentResponse struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure Deployment"`
|
||||
|
||||
Name string
|
||||
DeploymentSlot string
|
||||
Status DeploymentStatus
|
||||
Label string
|
||||
URL string `xml:"Url"`
|
||||
Configuration string
|
||||
RoleInstanceList []RoleInstance `xml:">RoleInstance"`
|
||||
UpgradeStatus UpgradeStatus
|
||||
UpgradeDomainCount int
|
||||
RoleList []Role `xml:">Role"`
|
||||
SdkVersion string
|
||||
Locked bool
|
||||
RollbackAllowed bool
|
||||
CreatedTime string
|
||||
LastModifiedTime string
|
||||
VirtualNetworkName string
|
||||
DNSServers []DNSServer `xml:"Dns>DnsServers>DnsServer"`
|
||||
LoadBalancers []LoadBalancer `xml:">LoadBalancer"`
|
||||
ExtendedProperties []ExtendedProperty `xml:">ExtendedProperty"`
|
||||
PersistentVMDowntime PersistentVMDowntime
|
||||
VirtualIPs []VirtualIP `xml:">VirtualIP"`
|
||||
ExtensionConfiguration string // cloud service extensions not fully implemented
|
||||
ReservedIPName string
|
||||
InternalDNSSuffix string `xml:"InternalDnsSuffix"`
|
||||
}
|
||||
|
||||
type DeploymentStatus string
|
||||
|
||||
const (
|
||||
DeploymentStatusRunning DeploymentStatus = "Running"
|
||||
DeploymentStatusSuspended DeploymentStatus = "Suspended"
|
||||
DeploymentStatusRunningTransitioning DeploymentStatus = "RunningTransitioning"
|
||||
DeploymentStatusSuspendedTransitioning DeploymentStatus = "SuspendedTransitioning"
|
||||
DeploymentStatusStarting DeploymentStatus = "Starting"
|
||||
DeploymentStatusSuspending DeploymentStatus = "Suspending"
|
||||
DeploymentStatusDeploying DeploymentStatus = "Deploying"
|
||||
DeploymentStatusDeleting DeploymentStatus = "Deleting"
|
||||
)
|
||||
|
||||
type RoleInstance struct {
|
||||
RoleName string
|
||||
InstanceName string
|
||||
InstanceStatus InstanceStatus
|
||||
ExtendedInstanceStatus string
|
||||
InstanceUpgradeDomain int
|
||||
InstanceFaultDomain int
|
||||
InstanceSize string
|
||||
InstanceStateDetails string
|
||||
InstanceErrorCode string
|
||||
IPAddress string `xml:"IpAddress"`
|
||||
InstanceEndpoints []InstanceEndpoint `xml:">InstanceEndpoint"`
|
||||
PowerState PowerState
|
||||
HostName string
|
||||
RemoteAccessCertificateThumbprint string
|
||||
GuestAgentStatus string // todo: implement
|
||||
ResourceExtensionStatusList []ResourceExtensionStatus `xml:">ResourceExtensionStatus"`
|
||||
PublicIPs []PublicIP `xml:">PublicIP"`
|
||||
}
|
||||
|
||||
type InstanceStatus string
|
||||
|
||||
const (
|
||||
InstanceStatusUnknown = "Unknown"
|
||||
InstanceStatusCreatingVM = "CreatingVM"
|
||||
InstanceStatusStartingVM = "StartingVM"
|
||||
InstanceStatusCreatingRole = "CreatingRole"
|
||||
InstanceStatusStartingRole = "StartingRole"
|
||||
InstanceStatusReadyRole = "ReadyRole"
|
||||
InstanceStatusBusyRole = "BusyRole"
|
||||
InstanceStatusStoppingRole = "StoppingRole"
|
||||
InstanceStatusStoppingVM = "StoppingVM"
|
||||
InstanceStatusDeletingVM = "DeletingVM"
|
||||
InstanceStatusStoppedVM = "StoppedVM"
|
||||
InstanceStatusRestartingRole = "RestartingRole"
|
||||
InstanceStatusCyclingRole = "CyclingRole"
|
||||
InstanceStatusFailedStartingRole = "FailedStartingRole"
|
||||
InstanceStatusFailedStartingVM = "FailedStartingVM"
|
||||
InstanceStatusUnresponsiveRole = "UnresponsiveRole"
|
||||
InstanceStatusStoppedDeallocated = "StoppedDeallocated"
|
||||
InstanceStatusPreparing = "Preparing"
|
||||
)
|
||||
|
||||
type InstanceEndpoint struct {
|
||||
Name string
|
||||
Vip string
|
||||
PublicPort int
|
||||
LocalPort int
|
||||
Protocol InputEndpointProtocol
|
||||
}
|
||||
|
||||
type PowerState string
|
||||
|
||||
const (
|
||||
PowerStateStarting PowerState = "Starting"
|
||||
PowerStateStarted PowerState = "Started"
|
||||
PowerStateStopping PowerState = "Stopping"
|
||||
PowerStateStopped PowerState = "Stopped"
|
||||
PowerStateUnknown PowerState = "Unknown"
|
||||
)
|
||||
|
||||
type ResourceExtensionStatus struct {
|
||||
HandlerName string
|
||||
Version string
|
||||
Status ResourceExtensionState
|
||||
Code string
|
||||
FormattedMessage FormattedMessage
|
||||
ExtensionSettingStatus ExtensionSettingStatus
|
||||
}
|
||||
|
||||
type ResourceExtensionState string
|
||||
|
||||
const (
|
||||
ResourceExtensionStateInstalling ResourceExtensionState = "Installing"
|
||||
ResourceExtensionStateReady ResourceExtensionState = "Ready"
|
||||
ResourceExtensionStateNotReady ResourceExtensionState = "NotReady"
|
||||
ResourceExtensionStateUnresponsive ResourceExtensionState = "Unresponsive"
|
||||
)
|
||||
|
||||
type FormattedMessage struct {
|
||||
Language string
|
||||
Message string
|
||||
}
|
||||
|
||||
type ExtensionSettingStatus struct {
|
||||
Timestamp string
|
||||
Name string
|
||||
Operation string
|
||||
Status ExtensionSettingState
|
||||
Code string
|
||||
FormattedMessage FormattedMessage
|
||||
SubStatusList []SubStatus `xml:">SubStatus"`
|
||||
}
|
||||
|
||||
type ExtensionSettingState string
|
||||
|
||||
const (
|
||||
ExtensionSettingStateTransitioning ExtensionSettingState = "transitioning"
|
||||
ExtensionSettingStateError ExtensionSettingState = "error"
|
||||
ExtensionSettingStateSuccess ExtensionSettingState = "success"
|
||||
ExtensionSettingStateWarning ExtensionSettingState = "warning"
|
||||
)
|
||||
|
||||
type SubStatus struct {
|
||||
Name string
|
||||
Status ExtensionSettingState
|
||||
FormattedMessage FormattedMessage
|
||||
}
|
||||
|
||||
type UpgradeStatus struct {
|
||||
UpgradeType UpgradeType
|
||||
CurrentUpgradeDomainState CurrentUpgradeDomainState
|
||||
CurrentUpgradeDomain int
|
||||
}
|
||||
|
||||
type UpgradeType string
|
||||
|
||||
const (
|
||||
UpgradeTypeAuto UpgradeType = "Auto"
|
||||
UpgradeTypeManual UpgradeType = "Manual"
|
||||
UpgradeTypeSimultaneous UpgradeType = "Simultaneous"
|
||||
)
|
||||
|
||||
type CurrentUpgradeDomainState string
|
||||
|
||||
const (
|
||||
CurrentUpgradeDomainStateBefore CurrentUpgradeDomainState = "Before"
|
||||
CurrentUpgradeDomainStateDuring CurrentUpgradeDomainState = "During"
|
||||
)
|
||||
|
||||
type ExtendedProperty struct {
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
type PersistentVMDowntime struct {
|
||||
StartTime string
|
||||
EndTime string
|
||||
Status string
|
||||
}
|
||||
|
||||
type VirtualIP struct {
|
||||
Address string
|
||||
IsReserved bool
|
||||
ReservedIPName string
|
||||
Type IPAddressType
|
||||
}
|
||||
|
||||
// Role contains the configuration sets that are used to create virtual
|
||||
// machines.
|
||||
type Role struct {
|
||||
RoleName string `xml:",omitempty"` // Specifies the name for the Virtual Machine.
|
||||
RoleType string `xml:",omitempty"` // Specifies the type of role to use. For Virtual Machines, this must be PersistentVMRole.
|
||||
ConfigurationSets []ConfigurationSet `xml:"ConfigurationSets>ConfigurationSet,omitempty"`
|
||||
ResourceExtensionReferences *[]ResourceExtensionReference `xml:"ResourceExtensionReferences>ResourceExtensionReference,omitempty"`
|
||||
VMImageName string `xml:",omitempty"` // Specifies the name of the VM Image that is to be used to create the Virtual Machine. If this element is used, the ConfigurationSets element is not used.
|
||||
MediaLocation string `xml:",omitempty"` // Required if the Virtual Machine is being created from a published VM Image. Specifies the location of the VHD file that is created when VMImageName specifies a published VM Image.
|
||||
AvailabilitySetName string `xml:",omitempty"` // Specifies the name of a collection of Virtual Machines. Virtual Machines specified in the same availability set are allocated to different nodes to maximize availability.
|
||||
DataVirtualHardDisks []DataVirtualHardDisk `xml:"DataVirtualHardDisks>DataVirtualHardDisk,omitempty"` // Contains the parameters that are used to add a data disk to a Virtual Machine. If you are creating a Virtual Machine by using a VM Image, this element is not used.
|
||||
OSVirtualHardDisk *OSVirtualHardDisk `xml:",omitempty"` // Contains the parameters that are used to create the operating system disk for a Virtual Machine. If you are creating a Virtual Machine by using a VM Image, this element is not used.
|
||||
RoleSize string `xml:",omitempty"` // Specifies the size of the Virtual Machine. The default size is Small.
|
||||
ProvisionGuestAgent bool `xml:",omitempty"` // Indicates whether the VM Agent is installed on the Virtual Machine. To run a resource extension in a Virtual Machine, this service must be installed.
|
||||
VMImageInput *VMImageInput `xml:",omitempty"` // When a VM Image is used to create a new PersistentVMRole, the DiskConfigurations in the VM Image are used to create new Disks for the new VM. This parameter can be used to resize the newly created Disks to a larger size than the underlying DiskConfigurations in the VM Image.
|
||||
|
||||
UseCertAuth bool `xml:"-"`
|
||||
CertPath string `xml:"-"`
|
||||
}
|
||||
|
||||
// VMImageInput is for when a VM Image is used to create a new PersistantVMRole,
|
||||
// the DiskConfigurations in the VM Image are used to create new Disks for the
|
||||
// new VM. This parameter can be used to resize the newly created Disks to a
|
||||
// larger size than the underlying DiskConfigurations in the VM Image.
|
||||
type VMImageInput struct {
|
||||
OSDiskConfiguration *OSDiskConfiguration `xml:",omitempty"` // This corresponds to the OSDiskConfiguration of the VM Image used to create a new role. The OSDiskConfiguration element is only available using version 2014-10-01 or higher.
|
||||
DataDiskConfigurations []DataDiskConfiguration `xml:">DataDiskConfiguration,omitempty"` // This corresponds to the DataDiskConfigurations of the VM Image used to create a new role. The DataDiskConfigurations element is only available using version 2014-10-01 or higher.
|
||||
}
|
||||
|
||||
// OSDiskConfiguration is used to resize the OS disk of a new VM created from a
|
||||
// previously saved VM image.
|
||||
type OSDiskConfiguration struct {
|
||||
ResizedSizeInGB int
|
||||
}
|
||||
|
||||
// DataDiskConfiguration is used to resize the data disks of a new VM created
|
||||
// from a previously saved VM image.
|
||||
type DataDiskConfiguration struct {
|
||||
OSDiskConfiguration
|
||||
Name string // The Name of the DataDiskConfiguration being referenced to.
|
||||
|
||||
}
|
||||
|
||||
// ResourceExtensionReference contains a collection of resource extensions that
|
||||
// are to be installed on the Virtual Machine. The VM Agent must be installed on
|
||||
// the Virtual Machine to install resource extensions. For more information, see
|
||||
// Manage Extensions:
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/dn606311.aspx.
|
||||
type ResourceExtensionReference struct {
|
||||
ReferenceName string
|
||||
Publisher string
|
||||
Name string
|
||||
Version string
|
||||
ParameterValues []ResourceExtensionParameter `xml:"ResourceExtensionParameterValues>ResourceExtensionParameterValue,omitempty"`
|
||||
State string
|
||||
}
|
||||
|
||||
// ResourceExtensionParameter specifies the key, value, and type of a parameter that is passed to the
|
||||
// resource extension when it is installed.
|
||||
type ResourceExtensionParameter struct {
|
||||
Key string
|
||||
Value string
|
||||
Type ResourceExtensionParameterType // If this value is set to Private, the parameter will not be returned by Get Deployment ().
|
||||
}
|
||||
|
||||
type ResourceExtensionParameterType string
|
||||
|
||||
// Enum values for ResourceExtensionParameterType
|
||||
const (
|
||||
ResourceExtensionParameterTypePublic ResourceExtensionParameterType = "Public"
|
||||
ResourceExtensionParameterTypePrivate ResourceExtensionParameterType = "Private"
|
||||
)
|
||||
|
||||
// DataVirtualHardDisk specifies the properties that are used to create a data
|
||||
// disk.
|
||||
type DataVirtualHardDisk struct {
|
||||
HostCaching vmdisk.HostCachingType `xml:",omitempty"` // Specifies the caching mode of the data disk. The default value is None.
|
||||
DiskLabel string `xml:",omitempty"` // If the disk that is being added is already registered in the subscription, this element is ignored. If a new disk is being created, this element is used to provide a description of the disk. The value of this element is only obtained programmatically and does not appear in the Management Portal.
|
||||
DiskName string `xml:",omitempty"` // If the disk that is being added is already registered in the subscription, this element is used to identify the disk to add. If a new disk and the associated VHD are being created by Azure, this element is not used and Azure assigns a unique name that is a combination of the deployment name, role name, and identifying number. The name of the disk must contain only alphanumeric characters, underscores, periods, or dashes. The name must not be longer than 256 characters. The name must not end with period or dash.
|
||||
Lun int `xml:",omitempty"` // Specifies the Logical Unit Number (LUN) for the data disk. If the disk is the first disk that is added, this element is optional and the default value of 0 is used. If more than one disk is being added, this element is required. Valid LUN values are 0 through 31.
|
||||
LogicalDiskSizeInGB int `xml:",omitempty"` // Specifies the size, in GB, of an empty disk to be attached to the Virtual Machine. If the disk that is being added is already registered in the subscription, this element is ignored. If the disk and VHD is being created by Azure as it is added, this element defines the size of the new disk.
|
||||
MediaLink string `xml:",omitempty"` // If the disk that is being added is already registered in the subscription or the VHD for the disk already exists in blob storage, this element is ignored. If a VHD file does not exist in blob storage, this element defines the location of the new VHD that is created when the new disk is added.
|
||||
SourceMediaLink string `xml:",omitempty"` // If the disk that is being added is already registered in the subscription or the VHD for the disk does not exist in blob storage, this element is ignored. If the VHD file exists in blob storage, this element defines the path to the VHD and a disk is registered from it and attached to the virtual machine.
|
||||
}
|
||||
|
||||
// OSVirtualHardDisk specifies the properties that are used to create an OS
|
||||
// disk.
|
||||
type OSVirtualHardDisk struct {
|
||||
HostCaching vmdisk.HostCachingType `xml:",omitempty"` // Specifies the caching mode of the data disk. The default value is None.
|
||||
DiskLabel string `xml:",omitempty"` // If the disk that is being added is already registered in the subscription, this element is ignored. If a new disk is being created, this element is used to provide a description of the disk. The value of this element is only obtained programmatically and does not appear in the Management Portal.
|
||||
DiskName string `xml:",omitempty"` // If the disk that is being added is already registered in the subscription, this element is used to identify the disk to add. If a new disk and the associated VHD are being created by Azure, this element is not used and Azure assigns a unique name that is a combination of the deployment name, role name, and identifying number. The name of the disk must contain only alphanumeric characters, underscores, periods, or dashes. The name must not be longer than 256 characters. The name must not end with period or dash.
|
||||
MediaLink string `xml:",omitempty"` // If the disk that is being added is already registered in the subscription or the VHD for the disk already exists in blob storage, this element is ignored. If a VHD file does not exist in blob storage, this element defines the location of the new VHD that is created when the new disk is added.
|
||||
SourceImageName string `xml:",omitempty"`
|
||||
OS string `xml:",omitempty"`
|
||||
RemoteSourceImageLink string `xml:",omitempty"` // Specifies a publicly accessible URI or a SAS URI to the location where an OS image is stored that is used to create the Virtual Machine. This location can be a different location than the user or platform image repositories in Azure. An image is always associated with a VHD, which is a .vhd file stored as a page blob in a storage account in Azure. If you specify the path to an image with this element, an associated VHD is created and you must use the MediaLink element to specify the location in storage where the VHD will be located. If this element is used, SourceImageName is not used.
|
||||
ResizedSizeInGB int `xml:",omitempty"`
|
||||
}
|
||||
|
||||
// ConfigurationSet specifies the configuration elements of the Virtual Machine.
|
||||
// The type attribute is required to prevent the administrator password from
|
||||
// being written to the operation history file.
|
||||
type ConfigurationSet struct {
|
||||
ConfigurationSetType ConfigurationSetType
|
||||
|
||||
// Windows provisioning:
|
||||
ComputerName string `xml:",omitempty"` // Optional. Specifies the computer name for the Virtual Machine. If you do not specify a computer name, one is assigned that is a combination of the deployment name, role name, and identifying number. Computer names must be 1 to 15 characters long.
|
||||
AdminPassword string `xml:",omitempty"` // Optional. Specifies the password to use for an administrator account on the Virtual Machine that is being created. If you are creating a Virtual Machine using an image, you must specify a name of an administrator account to be created on the machine using the AdminUsername element. You must use the AdminPassword element to specify the password of the administrator account that is being created. If you are creating a Virtual Machine using an existing specialized disk, this element is not used because the account should already exist on the disk.
|
||||
EnableAutomaticUpdates bool `xml:",omitempty"` // Optional. Specifies whether automatic updates are enabled for the Virtual Machine. The default value is true.
|
||||
TimeZone string `xml:",omitempty"` // Optional. Specifies the time zone for the Virtual Machine.
|
||||
DomainJoin *DomainJoin `xml:",omitempty"` // Optional. Contains properties that define a domain to which the Virtual Machine will be joined.
|
||||
StoredCertificateSettings []CertificateSetting `xml:">StoredCertificateSetting,omitempty"` // Optional. Contains a list of service certificates with which to provision to the new Virtual Machine.
|
||||
WinRMListeners *[]WinRMListener `xml:"WinRM>Listeners>Listener,omitempty"` // Optional. Contains configuration settings for the Windows Remote Management service on the Virtual Machine. This enables remote Windows PowerShell.
|
||||
AdminUsername string `xml:",omitempty"` // Optional. Specifies the name of the administrator account that is created to access the Virtual Machine. If you are creating a Virtual Machine using an image, you must specify a name of an administrator account to be created by using this element. You must use the AdminPassword element to specify the password of the administrator account that is being created. If you are creating a Virtual Machine using an existing specialized disk, this element is not used because the account should already exist on the disk.
|
||||
AdditionalUnattendContent string `xml:",omitempty"` // Specifies additional base-64 encoded XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup.
|
||||
|
||||
// Linux provisioning:
|
||||
HostName string `xml:",omitempty"` // Required. Specifies the host name for the Virtual Machine. Host names must be 1 to 64 characters long.
|
||||
UserName string `xml:",omitempty"` // Required. Specifies the name of a user account to be created in the sudoer group of the Virtual Machine. User account names must be 1 to 32 characters long.
|
||||
UserPassword string `xml:",omitempty"` // Required. Specifies the password for the user account. Passwords must be 6 to 72 characters long.
|
||||
DisableSSHPasswordAuthentication string `xml:"DisableSshPasswordAuthentication,omitempty"` // Optional. Specifies whether SSH password authentication is disabled. By default this value is set to true.
|
||||
SSH *SSH `xml:",omitempty"` // Optional. Specifies the SSH public keys and key pairs to use with the Virtual Machine.
|
||||
|
||||
// In WindowsProvisioningConfiguration: The base-64 encoded string is decoded to a binary array that is saved as a file on the Virtual Machine. The maximum length of the binary array is 65535 bytes. The file is saved to %SYSTEMDRIVE%\AzureData\CustomData.bin. If the file exists, it is overwritten. The security on directory is set to System:Full Control and Administrators:Full Control.
|
||||
// In LinuxProvisioningConfiguration: The base-64 encoded string is located in the ovf-env.xml file on the ISO of the Virtual Machine. The file is copied to /var/lib/waagent/ovf-env.xml by the Azure Linux Agent. The Azure Linux Agent will also place the base-64 encoded data in /var/lib/waagent/CustomData during provisioning. The maximum length of the binary array is 65535 bytes.
|
||||
CustomData string `xml:",omitempty"` // Specifies a base-64 encoded string of custom data.
|
||||
|
||||
// Network configuration:
|
||||
InputEndpoints []InputEndpoint `xml:">InputEndpoint,omitempty"` // Optional in NetworkConfiguration. Contains a collection of external endpoints for the Virtual Machine.
|
||||
SubnetNames []string `xml:">SubnetName,omitempty"` // Required if StaticVirtualNetworkIPAddress is specified; otherwise, optional in NetworkConfiguration. Contains a list of subnets to which the Virtual Machine will belong.
|
||||
StaticVirtualNetworkIPAddress string `xml:",omitempty"` // Specifies the internal IP address for the Virtual Machine in a Virtual Network. If you specify this element, you must also specify the SubnetNames element with only one subnet defined. The IP address specified in this element must belong to the subnet that is defined in SubnetNames and it should not be the one of the first four IP addresses or the last IP address in the subnet. Deploying web roles or worker roles into a subnet that has Virtual Machines with StaticVirtualNetworkIPAddress defined is not supported.
|
||||
NetworkSecurityGroup string `xml:",omitempty"` // Optional in NetworkConfiguration. Represents the name of the Network Security Group that will be associated with the Virtual Machine. Network Security Group must exist in the context of subscription and be created in same region to which the virtual machine will be deployed.
|
||||
PublicIPs []PublicIP `xml:">PublicIP,omitempty"` // Contains a public IP address that can be used in addition to the default virtual IP address for the Virtual Machine.
|
||||
}
|
||||
|
||||
type ConfigurationSetType string
|
||||
|
||||
// Enum values for ConfigurationSetType
|
||||
const (
|
||||
ConfigurationSetTypeWindowsProvisioning ConfigurationSetType = "WindowsProvisioningConfiguration"
|
||||
ConfigurationSetTypeLinuxProvisioning ConfigurationSetType = "LinuxProvisioningConfiguration"
|
||||
ConfigurationSetTypeNetwork ConfigurationSetType = "NetworkConfiguration"
|
||||
)
|
||||
|
||||
// DomainJoin contains properties that define a domain to which the Virtual
|
||||
// Machine will be joined.
|
||||
type DomainJoin struct {
|
||||
Credentials Credentials `xml:",omitempty"` // Specifies the credentials to use to join the Virtual Machine to the domain.
|
||||
JoinDomain string `xml:",omitempty"` // Specifies the domain to join.
|
||||
MachineObjectOU string `xml:",omitempty"` // Specifies the Lightweight Directory Access Protocol (LDAP) X 500-distinguished name of the organizational unit (OU) in which the computer account is created. This account is in Active Directory on a domain controller in the domain to which the computer is being joined.
|
||||
}
|
||||
|
||||
// Credentials specifies the credentials to use to join the Virtual Machine to
|
||||
// the domain. If Domain is not specified, Username must specify the user
|
||||
// principal name (UPN) format (user@fully-qualified-DNS-domain) or the fully-
|
||||
// qualified-DNS-domain\username format.
|
||||
type Credentials struct {
|
||||
Domain string // Specifies the name of the domain used to authenticate an account. The value is a fully qualified DNS domain.
|
||||
Username string // Specifies a user name in the domain that can be used to join the domain.
|
||||
Password string // Specifies the password to use to join the domain.
|
||||
}
|
||||
|
||||
// CertificateSetting specifies the parameters for the certificate which to
|
||||
// provision to the new Virtual Machine.
|
||||
type CertificateSetting struct {
|
||||
StoreLocation string // Required. Specifies the certificate store location on the Virtual Machine. The only supported value is "LocalMachine".
|
||||
StoreName string // Required. Specifies the name of the certificate store from which the certificate is retrieved. For example, "My".
|
||||
Thumbprint string // Required. Specifies the thumbprint of the certificate. The thumbprint must specify an existing service certificate.
|
||||
}
|
||||
|
||||
// WinRMListener specifies the protocol and certificate information for a WinRM
|
||||
// listener.
|
||||
type WinRMListener struct {
|
||||
Protocol WinRMProtocol // Specifies the protocol of listener.
|
||||
CertificateThumbprint string `xml:",omitempty"` // Specifies the certificate thumbprint for the secure connection. If this value is not specified, a self-signed certificate is generated and used for the Virtual Machine.
|
||||
}
|
||||
|
||||
type WinRMProtocol string
|
||||
|
||||
// Enum values for WinRMProtocol
|
||||
const (
|
||||
WinRMProtocolHTTP WinRMProtocol = "Http"
|
||||
WinRMProtocolHTTPS WinRMProtocol = "Https"
|
||||
)
|
||||
|
||||
// SSH specifies the SSH public keys and key pairs to use with the Virtual Machine.
|
||||
type SSH struct {
|
||||
PublicKeys []PublicKey `xml:">PublicKey"`
|
||||
KeyPairs []KeyPair `xml:">KeyPair"`
|
||||
}
|
||||
|
||||
// PublicKey specifies a public SSH key.
|
||||
type PublicKey struct {
|
||||
Fingerprint string // Specifies the SHA1 fingerprint of an X509 certificate associated with the cloud service and includes the SSH public key.
|
||||
// Specifies the full path of a file, on the Virtual Machine, where the SSH public key is stored. If
|
||||
// the file already exists, the specified key is appended to the file.
|
||||
Path string // Usually /home/username/.ssh/authorized_keys
|
||||
}
|
||||
|
||||
// KeyPair specifies an SSH keypair.
|
||||
type KeyPair struct {
|
||||
Fingerprint string // Specifies the SHA1 fingerprint of an X509 certificate that is associated with the cloud service and includes the SSH keypair.
|
||||
// Specifies the full path of a file, on the virtual machine, which stores the SSH private key. The
|
||||
// file is overwritten when multiple keys are written to it. The SSH public key is stored in the same
|
||||
// directory and has the same name as the private key file with .pub suffix.
|
||||
Path string // Usually /home/username/.ssh/id_rsa
|
||||
}
|
||||
|
||||
// InputEndpoint specifies the properties that define an external endpoint for
|
||||
// the Virtual Machine.
|
||||
type InputEndpoint struct {
|
||||
LocalPort int // Specifies the internal port on which the Virtual Machine is listening.
|
||||
Name string // Specifies the name of the external endpoint.
|
||||
Port int // Specifies the external port to use for the endpoint.
|
||||
Protocol InputEndpointProtocol //Specifies the transport protocol for the endpoint.
|
||||
Vip string `xml:",omitempty"`
|
||||
}
|
||||
|
||||
type InputEndpointProtocol string
|
||||
|
||||
// Enum values for InputEndpointProtocol
|
||||
const (
|
||||
InputEndpointProtocolTCP InputEndpointProtocol = "TCP"
|
||||
InputEndpointProtocolUDP InputEndpointProtocol = "UDP"
|
||||
)
|
||||
|
||||
// PublicIP contains a public IP address that can be used in addition to default
|
||||
// virtual IP address for the Virtual Machine.
|
||||
type PublicIP struct {
|
||||
Name string // Specifies the name of the public IP address.
|
||||
Address string // Specifies the IP address.
|
||||
IdleTimeoutInMinutes int `xml:",omitempty"` // Specifies the timeout for the TCP idle connection. The value can be set between 4 and 30 minutes. The default value is 4 minutes. This element is only used when the protocol is set to TCP.
|
||||
}
|
||||
|
||||
// ServiceCertificate contains a certificate for adding it to a hosted service
|
||||
type ServiceCertificate struct {
|
||||
XMLName xml.Name `xml:"CertificateFile"`
|
||||
Data string
|
||||
CertificateFormat string
|
||||
Password string `xml:",omitempty"`
|
||||
}
|
||||
|
||||
// StartRoleOperation contains the information for starting a Role.
|
||||
type StartRoleOperation struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure StartRoleOperation"`
|
||||
OperationType string
|
||||
}
|
||||
|
||||
type PostShutdownAction string
|
||||
|
||||
// Enum values for PostShutdownAction
|
||||
const (
|
||||
PostShutdownActionStopped PostShutdownAction = "Stopped"
|
||||
PostShutdownActionStoppedDeallocated PostShutdownAction = "StoppedDeallocated"
|
||||
)
|
||||
|
||||
// ShutdownRoleOperation contains the information for shutting down a Role.
|
||||
type ShutdownRoleOperation struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure ShutdownRoleOperation"`
|
||||
OperationType string
|
||||
PostShutdownAction PostShutdownAction
|
||||
}
|
||||
|
||||
// RestartRoleOperation contains the information for restarting a Role.
|
||||
type RestartRoleOperation struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure RestartRoleOperation"`
|
||||
OperationType string
|
||||
}
|
||||
|
||||
// CaptureRoleOperation contains the information for capturing a Role
|
||||
type CaptureRoleOperation struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure CaptureRoleOperation"`
|
||||
OperationType string
|
||||
PostCaptureAction PostCaptureAction
|
||||
ProvisioningConfiguration *ConfigurationSet `xml:",omitempty"`
|
||||
TargetImageLabel string
|
||||
TargetImageName string
|
||||
}
|
||||
|
||||
type PostCaptureAction string
|
||||
|
||||
// Enum values for PostCaptureAction
|
||||
const (
|
||||
PostCaptureActionDelete PostCaptureAction = "Delete"
|
||||
PostCaptureActionReprovision PostCaptureAction = "Reprovision"
|
||||
)
|
||||
|
||||
// RoleSizeList contains a list of the available role sizes
|
||||
type RoleSizeList struct {
|
||||
XMLName xml.Name `xml:"RoleSizes"`
|
||||
RoleSizes []RoleSize `xml:"RoleSize"`
|
||||
}
|
||||
|
||||
// RoleSize contains a detailed explanation of a role size
|
||||
type RoleSize struct {
|
||||
Name string
|
||||
Label string
|
||||
Cores int
|
||||
MemoryInMb int
|
||||
SupportedByWebWorkerRoles bool
|
||||
SupportedByVirtualMachines bool
|
||||
MaxDataDiskCount int
|
||||
WebWorkerResourceDiskSizeInMb int
|
||||
VirtualMachineResourceDiskSizeInMb int
|
||||
}
|
||||
|
||||
// DNSServer contains the definition of a DNS server for virtual machine deployment
|
||||
type DNSServer struct {
|
||||
Name string
|
||||
Address string
|
||||
}
|
||||
|
||||
// LoadBalancer contains the definition of a load balancer for virtual machine deployment
|
||||
type LoadBalancer struct {
|
||||
Name string // Specifies the name of the internal load balancer.
|
||||
Type IPAddressType `xml:"FrontendIpConfiguration>Type"` // Specifies the type of virtual IP address that is provided by the load balancer. The only allowable value is Private.
|
||||
SubnetName string `xml:"FrontendIpConfiguration>SubnetName,omitempty"` // Required if the deployment exists in a virtual network and a StaticVirtualNetworkIPAddress is assigned. Specifies the subnet of the virtual network that the load balancer uses. The virtual IP address that is managed by the load balancer is contained in this subnet.
|
||||
StaticVirtualNetworkIPAddress string `xml:"FrontendIpConfiguration>StaticVirtualNetworkIPAddress,omitempty"` // Specifies a specific virtual IP address that the load balancer uses from the subnet in the virtual network.
|
||||
}
|
||||
|
||||
type IPAddressType string
|
||||
|
||||
// Enum values for IPAddressType
|
||||
const (
|
||||
IPAddressTypePrivate IPAddressType = "Private" // Only allowed value (currently) for IPAddressType
|
||||
)
|
||||
|
||||
type ResourceExtensions struct {
|
||||
List []ResourceExtension `xml:"ResourceExtension"`
|
||||
}
|
||||
|
||||
type ResourceExtension struct {
|
||||
Publisher string
|
||||
Name string
|
||||
Version string
|
||||
Label string
|
||||
Description string
|
||||
PublicConfigurationSchema string
|
||||
PrivateConfigurationSchema string
|
||||
SampleConfig string
|
||||
ReplicationCompleted string
|
||||
Eula string
|
||||
PrivacyURI string `xml:"PrivacyUri"`
|
||||
HomepageURI string `xml:"HomepageUri"`
|
||||
IsJSONExtension bool `xml:"IsJsonExtension"`
|
||||
IsInternalExtension bool
|
||||
DisallowMajorVersionUpgrade bool
|
||||
CompanyName string
|
||||
SupportedOS string
|
||||
PublishedDate string
|
||||
}
|
||||
|
||||
type PersistentVMRole struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure PersistentVMRole"`
|
||||
Role
|
||||
}
|
||||
Generated
Vendored
+299
@@ -0,0 +1,299 @@
|
||||
package virtualmachine
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDocumentedDeploymentRequest(t *testing.T) {
|
||||
// xml based on https://msdn.microsoft.com/en-us/library/azure/jj157194.aspx
|
||||
// fixed typos, replaced strongly typed fields with values of correct type
|
||||
xmlString := `<Deployment xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Name>name-of-deployment</Name>
|
||||
<DeploymentSlot>deployment-environment</DeploymentSlot>
|
||||
<Label>identifier-of-deployment</Label>
|
||||
<RoleList>
|
||||
<Role>
|
||||
<RoleName>name-of-the-virtual-machine</RoleName>
|
||||
<RoleType>PersistentVMRole</RoleType>
|
||||
<ConfigurationSets>
|
||||
<ConfigurationSet i:type="WindowsProvisioningConfigurationSet">
|
||||
<ConfigurationSetType>WindowsProvisioningConfiguration</ConfigurationSetType>
|
||||
<ComputerName>name-of-computer</ComputerName>
|
||||
<AdminPassword>administrator-password</AdminPassword>
|
||||
<EnableAutomaticUpdates>true</EnableAutomaticUpdates>
|
||||
<TimeZone>time-zone</TimeZone>
|
||||
<DomainJoin>
|
||||
<Credentials>
|
||||
<Domain>domain-to-join</Domain>
|
||||
<Username>user-name-in-the-domain</Username>
|
||||
<Password>password-for-the-user-name</Password>
|
||||
</Credentials>
|
||||
<JoinDomain>domain-to-join</JoinDomain>
|
||||
<MachineObjectOU>distinguished-name-of-the-ou</MachineObjectOU>
|
||||
</DomainJoin>
|
||||
<StoredCertificateSettings>
|
||||
<CertificateSetting>
|
||||
<StoreLocation>LocalMachine</StoreLocation>
|
||||
<StoreName>name-of-store-on-the-machine</StoreName>
|
||||
<Thumbprint>certificate-thumbprint</Thumbprint>
|
||||
</CertificateSetting>
|
||||
</StoredCertificateSettings>
|
||||
<WinRM>
|
||||
<Listeners>
|
||||
<Listener>
|
||||
<Protocol>listener-protocol</Protocol>
|
||||
</Listener>
|
||||
<Listener>
|
||||
<CertificateThumbprint>certificate-thumbprint</CertificateThumbprint>
|
||||
<Protocol>listener-protocol</Protocol>
|
||||
</Listener>
|
||||
</Listeners>
|
||||
</WinRM>
|
||||
<AdminUsername>name-of-administrator-account</AdminUsername>
|
||||
<CustomData>base-64-encoded-data</CustomData>
|
||||
<AdditionalUnattendContent>
|
||||
<Passes>
|
||||
<UnattendPass>
|
||||
<PassName>name-of-pass</PassName>
|
||||
<Components>
|
||||
<UnattendComponent>
|
||||
<ComponentName>name-of-component</ComponentName>
|
||||
<ComponentSettings>
|
||||
<ComponentSetting>
|
||||
<SettingName>name-of-setting</SettingName>
|
||||
<Content>base-64-encoded-XML-content</Content>
|
||||
</ComponentSetting>
|
||||
</ComponentSettings>
|
||||
</UnattendComponent>
|
||||
</Components>
|
||||
</UnattendPass>
|
||||
</Passes>
|
||||
</AdditionalUnattendContent>
|
||||
</ConfigurationSet>
|
||||
<ConfigurationSet i:type="LinuxProvisioningConfigurationSet">
|
||||
<ConfigurationSetType>LinuxProvisioningConfiguration</ConfigurationSetType>
|
||||
<HostName>host-name-for-the-virtual-machine</HostName>
|
||||
<UserName>new-user-name</UserName>
|
||||
<UserPassword>password-for-the-new-user</UserPassword>
|
||||
<DisableSshPasswordAuthentication>true</DisableSshPasswordAuthentication>
|
||||
<SSH>
|
||||
<PublicKeys>
|
||||
<PublicKey>
|
||||
<FingerPrint>certificate-fingerprint</FingerPrint>
|
||||
<Path>SSH-public-key-storage-location</Path>
|
||||
</PublicKey>
|
||||
</PublicKeys>
|
||||
<KeyPairs>
|
||||
<KeyPair>
|
||||
<FingerPrint>certificate-fingerprint</FingerPrint>
|
||||
<Path>SSH-public-key-storage-location</Path>
|
||||
</KeyPair>
|
||||
</KeyPairs>
|
||||
</SSH>
|
||||
<CustomData>base-64-encoded-data</CustomData>
|
||||
</ConfigurationSet>
|
||||
<ConfigurationSet>
|
||||
<ConfigurationSetType>NetworkConfiguration</ConfigurationSetType>
|
||||
<InputEndpoints>
|
||||
<InputEndpoint>
|
||||
<LoadBalancedEndpointSetName>name-of-load-balanced-set</LoadBalancedEndpointSetName>
|
||||
<LocalPort>22</LocalPort>
|
||||
<Name>ZZH</Name>
|
||||
<Port>33</Port>
|
||||
<LoadBalancerProbe>
|
||||
<Path>/probe/me</Path>
|
||||
<Port>80</Port>
|
||||
<Protocol>http</Protocol>
|
||||
<IntervalInSeconds>30</IntervalInSeconds>
|
||||
<TimeoutInSeconds>5</TimeoutInSeconds>
|
||||
</LoadBalancerProbe>
|
||||
<Protocol>endpoint-protocol</Protocol>
|
||||
<EnableDirectServerReturn>enable-direct-server-return</EnableDirectServerReturn>
|
||||
<EndpointACL>
|
||||
<Rules>
|
||||
<Rule>
|
||||
<Order>priority-of-the-rule</Order>
|
||||
<Action>permit-rule</Action>
|
||||
<RemoteSubnet>subnet-of-the-rule</RemoteSubnet>
|
||||
<Description>description-of-the-rule</Description>
|
||||
</Rule>
|
||||
</Rules>
|
||||
</EndpointACL>
|
||||
<LoadBalancerName>name-of-internal-loadbalancer</LoadBalancerName>
|
||||
<IdleTimeoutInMinutes>9</IdleTimeoutInMinutes>
|
||||
</InputEndpoint>
|
||||
</InputEndpoints>
|
||||
<SubnetNames>
|
||||
<SubnetName>name-of-subnet</SubnetName>
|
||||
</SubnetNames>
|
||||
<StaticVirtualNetworkIPAddress>ip-address</StaticVirtualNetworkIPAddress>
|
||||
<PublicIPs>
|
||||
<PublicIP>
|
||||
<Name>name-of-public-ip</Name>
|
||||
<IdleTimeoutInMinutes>11</IdleTimeoutInMinutes>
|
||||
</PublicIP>
|
||||
</PublicIPs>
|
||||
</ConfigurationSet>
|
||||
</ConfigurationSets>
|
||||
<ResourceExtensionReferences>
|
||||
<ResourceExtensionReference>
|
||||
<ReferenceName>name-of-reference</ReferenceName>
|
||||
<Publisher>name-of-publisher</Publisher>
|
||||
<Name>name-of-extension</Name>
|
||||
<Version>version-of-extension</Version>
|
||||
<ResourceExtensionParameterValues>
|
||||
<ResourceExtensionParameterValue>
|
||||
<Key>name-of-parameter-key</Key>
|
||||
<Value>parameter-value</Value>
|
||||
<Type>type-of-parameter</Type>
|
||||
</ResourceExtensionParameterValue>
|
||||
</ResourceExtensionParameterValues>
|
||||
<State>state-of-resource</State>
|
||||
<Certificates>
|
||||
<Certificate>
|
||||
<Thumbprint>certificate-thumbprint</Thumbprint>
|
||||
<ThumbprintAlgorithm>certificate-algorithm</ThumbprintAlgorithm>
|
||||
</Certificate>
|
||||
</Certificates>
|
||||
</ResourceExtensionReference>
|
||||
</ResourceExtensionReferences>
|
||||
<VMImageName>name-of-vm-image</VMImageName>
|
||||
<MediaLocation>path-to-vhd</MediaLocation>
|
||||
<AvailabilitySetName>name-of-availability-set</AvailabilitySetName>
|
||||
<DataVirtualHardDisks>
|
||||
<DataVirtualHardDisk>
|
||||
<HostCaching>caching-mode</HostCaching>
|
||||
<DiskLabel>label-of-data-disk</DiskLabel>
|
||||
<DiskName>name-of-disk</DiskName>
|
||||
<Lun>0</Lun>
|
||||
<LogicalDiskSizeInGB>50</LogicalDiskSizeInGB>
|
||||
<MediaLink>path-to-vhd</MediaLink>
|
||||
</DataVirtualHardDisk>
|
||||
</DataVirtualHardDisks>
|
||||
<OSVirtualHardDisk>
|
||||
<HostCaching>caching-mode</HostCaching>
|
||||
<DiskLabel>label-of-operating-system-disk</DiskLabel>
|
||||
<DiskName>name-of-disk</DiskName>
|
||||
<MediaLink>path-to-vhd</MediaLink>
|
||||
<SourceImageName>name-of-source-image</SourceImageName>
|
||||
<OS>operating-system-of-image</OS>
|
||||
<RemoteSourceImageLink>path-to-source-image</RemoteSourceImageLink>
|
||||
<ResizedSizeInGB>125</ResizedSizeInGB>
|
||||
</OSVirtualHardDisk>
|
||||
<RoleSize>size-of-virtual-machine</RoleSize>
|
||||
<ProvisionGuestAgent>true</ProvisionGuestAgent>
|
||||
<VMImageInput>
|
||||
<OSDiskConfiguration>
|
||||
<ResizedSizeInGB>126</ResizedSizeInGB>
|
||||
</OSDiskConfiguration>
|
||||
<DataDiskConfigurations>
|
||||
<DataDiskConfiguration>
|
||||
<Name>disk-name</Name>
|
||||
<ResizedSizeInGB>127</ResizedSizeInGB>
|
||||
</DataDiskConfiguration>
|
||||
</DataDiskConfigurations>
|
||||
</VMImageInput>
|
||||
</Role>
|
||||
</RoleList>
|
||||
<VirtualNetworkName>name-of-virtual-network</VirtualNetworkName>
|
||||
<Dns>
|
||||
<DnsServers>
|
||||
<DnsServer>
|
||||
<Name>dns-name</Name>
|
||||
<Address>dns-ip-address</Address>
|
||||
</DnsServer>
|
||||
</DnsServers>
|
||||
</Dns>
|
||||
<ReservedIPName>name-of-reserved-ip</ReservedIPName>
|
||||
<LoadBalancers>
|
||||
<LoadBalancer>
|
||||
<Name>name-of-internal-load-balancer</Name>
|
||||
<FrontendIpConfiguration>
|
||||
<Type>Private</Type>
|
||||
<SubnetName>name-of-subnet</SubnetName>
|
||||
<StaticVirtualNetworkIPAddress>static-ip-address</StaticVirtualNetworkIPAddress>
|
||||
</FrontendIpConfiguration>
|
||||
</LoadBalancer>
|
||||
</LoadBalancers>
|
||||
</Deployment>`
|
||||
|
||||
deployment := DeploymentRequest{}
|
||||
if err := xml.Unmarshal([]byte(xmlString), &deployment); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if deployment.Name != "name-of-deployment" {
|
||||
t.Fatalf("Expected deployment.Name=\"name-of-deployment\", but got \"%s\"",
|
||||
deployment.Name)
|
||||
}
|
||||
|
||||
// ======
|
||||
|
||||
t.Logf("deployment.RoleList[0]: %+v", deployment.RoleList[0])
|
||||
if expected := "name-of-the-virtual-machine"; deployment.RoleList[0].RoleName != expected {
|
||||
t.Fatalf("Expected deployment.RoleList[0].RoleName=%v, but got %v", expected, deployment.RoleList[0].RoleName)
|
||||
}
|
||||
|
||||
// ======
|
||||
|
||||
t.Logf("deployment.DNSServers[0]: %+v", deployment.DNSServers[0])
|
||||
if deployment.DNSServers[0].Name != "dns-name" {
|
||||
t.Fatalf("Expected deployment.DNSServers[0].Name=\"dns-name\", but got \"%s\"",
|
||||
deployment.DNSServers[0].Name)
|
||||
}
|
||||
|
||||
// ======
|
||||
|
||||
t.Logf("deployment.LoadBalancers[0]: %+v", deployment.LoadBalancers[0])
|
||||
if deployment.LoadBalancers[0].Name != "name-of-internal-load-balancer" {
|
||||
t.Fatalf("Expected deployment.LoadBalancers[0].Name=\"name-of-internal-load-balancer\", but got \"%s\"",
|
||||
deployment.LoadBalancers[0].Name)
|
||||
}
|
||||
|
||||
if deployment.LoadBalancers[0].Type != IPAddressTypePrivate {
|
||||
t.Fatalf("Expected deployment.LoadBalancers[0].Type=IPAddressTypePrivate, but got \"%s\"",
|
||||
deployment.LoadBalancers[0].Type)
|
||||
}
|
||||
|
||||
if deployment.LoadBalancers[0].StaticVirtualNetworkIPAddress != "static-ip-address" {
|
||||
t.Fatalf("Expected deployment.LoadBalancers[0].StaticVirtualNetworkIPAddress=\"static-ip-address\", but got \"%s\"",
|
||||
deployment.LoadBalancers[0].StaticVirtualNetworkIPAddress)
|
||||
}
|
||||
|
||||
// ======
|
||||
|
||||
extensionReferences := (*deployment.RoleList[0].ResourceExtensionReferences)
|
||||
t.Logf("(*deployment.RoleList[0].ResourceExtensionReferences)[0]: %+v", extensionReferences[0])
|
||||
if extensionReferences[0].Name != "name-of-extension" {
|
||||
t.Fatalf("Expected (*deployment.RoleList[0].ResourceExtensionReferences)[0].Name=\"name-of-extension\", but got \"%s\"",
|
||||
extensionReferences[0].Name)
|
||||
}
|
||||
|
||||
if extensionReferences[0].ParameterValues[0].Key != "name-of-parameter-key" {
|
||||
t.Fatalf("Expected (*deployment.RoleList[0].ResourceExtensionReferences)[0].ParameterValues[0].Key=\"name-of-parameter-key\", but got %v",
|
||||
extensionReferences[0].ParameterValues[0].Key)
|
||||
}
|
||||
|
||||
// ======
|
||||
|
||||
if deployment.RoleList[0].VMImageInput.DataDiskConfigurations[0].ResizedSizeInGB != 127 {
|
||||
t.Fatalf("Expected deployment.RoleList[0].VMImageInput.DataDiskConfigurations[0].ResizedSizeInGB=127, but got %v",
|
||||
deployment.RoleList[0].VMImageInput.DataDiskConfigurations[0].ResizedSizeInGB)
|
||||
}
|
||||
|
||||
// ======
|
||||
|
||||
winRMlisteners := *deployment.RoleList[0].ConfigurationSets[0].WinRMListeners
|
||||
if string(winRMlisteners[0].Protocol) != "listener-protocol" {
|
||||
t.Fatalf("Expected winRMlisteners[0].Protocol to be listener-protocol, but got %s",
|
||||
string(winRMlisteners[0].Protocol))
|
||||
}
|
||||
|
||||
winRMlisteners2 := *deployment.RoleList[0].ConfigurationSets[0].WinRMListeners
|
||||
if winRMlisteners2[1].CertificateThumbprint != "certificate-thumbprint" {
|
||||
t.Fatalf("Expected winRMlisteners2[1].CertificateThumbprint to be certificate-thumbprint, but got %s",
|
||||
winRMlisteners2[1].CertificateThumbprint)
|
||||
}
|
||||
|
||||
}
|
||||
Generated
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
package virtualmachine
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
)
|
||||
|
||||
const (
|
||||
azureResourceExtensionsURL = "services/resourceextensions"
|
||||
)
|
||||
|
||||
// GetResourceExtensions lists the resource extensions that are available to add
|
||||
// to a virtual machine.
|
||||
//
|
||||
// See https://msdn.microsoft.com/en-us/library/azure/dn495441.aspx
|
||||
func (c VirtualMachineClient) GetResourceExtensions() (extensions []ResourceExtension, err error) {
|
||||
data, err := c.client.SendAzureGetRequest(azureResourceExtensionsURL)
|
||||
if err != nil {
|
||||
return extensions, err
|
||||
}
|
||||
|
||||
var response ResourceExtensions
|
||||
err = xml.Unmarshal(data, &response)
|
||||
extensions = response.List
|
||||
return
|
||||
}
|
||||
Generated
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
package virtualmachine
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management/testutils"
|
||||
)
|
||||
|
||||
func TestAzureGetResourceExtensions(t *testing.T) {
|
||||
client := testutils.GetTestClient(t)
|
||||
|
||||
list, err := NewClient(client).GetResourceExtensions()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Logf("Found %d extensions", len(list))
|
||||
if len(list) == 0 {
|
||||
t.Fatal("Huh, no resource extensions at all? Something must be wrong.")
|
||||
}
|
||||
|
||||
for _, extension := range list {
|
||||
if extension.Name == "" {
|
||||
t.Fatalf("Resource with empty name? Something must have gone wrong with serialization: %+v", extension)
|
||||
}
|
||||
}
|
||||
}
|
||||
+230
@@ -0,0 +1,230 @@
|
||||
// Package virtualmachinedisk provides a client for Virtual Machine Disks.
|
||||
package virtualmachinedisk
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
const (
|
||||
addDataDiskURL = "services/hostedservices/%s/deployments/%s/roles/%s/DataDisks"
|
||||
addDiskURL = "services/disks"
|
||||
deleteDataDiskURL = "services/hostedservices/%s/deployments/%s/roles/%s/DataDisks/%d"
|
||||
deleteDiskURL = "services/disks/%s"
|
||||
getDataDiskURL = "services/hostedservices/%s/deployments/%s/roles/%s/DataDisks/%d"
|
||||
getDiskURL = "services/disks/%s"
|
||||
listDisksURL = "services/disks"
|
||||
updateDataDiskURL = "services/hostedservices/%s/deployments/%s/roles/%s/DataDisks/%d"
|
||||
updateDiskURL = "services/disks/%s"
|
||||
|
||||
errParamNotSpecified = "Parameter %s is not specified."
|
||||
)
|
||||
|
||||
//NewClient is used to instantiate a new DiskClient from an Azure client
|
||||
func NewClient(client management.Client) DiskClient {
|
||||
return DiskClient{client: client}
|
||||
}
|
||||
|
||||
// AddDataDisk adds a data disk to a Virtual Machine
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/jj157199.aspx
|
||||
func (c DiskClient) AddDataDisk(
|
||||
service string,
|
||||
deployment string,
|
||||
role string,
|
||||
params CreateDataDiskParameters) (management.OperationID, error) {
|
||||
if service == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "service")
|
||||
}
|
||||
if deployment == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "deployment")
|
||||
}
|
||||
if role == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(addDataDiskURL, service, deployment, role)
|
||||
|
||||
req, err := xml.Marshal(params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return c.client.SendAzurePostRequest(requestURL, req)
|
||||
}
|
||||
|
||||
// AddDisk adds an operating system disk or data disk to the user image repository
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/jj157178.aspx
|
||||
func (c DiskClient) AddDisk(params CreateDiskParameters) (management.OperationID, error) {
|
||||
req, err := xml.Marshal(params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return c.client.SendAzurePostRequest(addDiskURL, req)
|
||||
}
|
||||
|
||||
// DeleteDataDisk removes the specified data disk from a Virtual Machine
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/jj157179.aspx
|
||||
func (c DiskClient) DeleteDataDisk(
|
||||
service string,
|
||||
deployment string,
|
||||
role string,
|
||||
lun int,
|
||||
deleteVHD bool) (management.OperationID, error) {
|
||||
if service == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "service")
|
||||
}
|
||||
if deployment == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "deployment")
|
||||
}
|
||||
if role == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(deleteDataDiskURL, service, deployment, role, lun)
|
||||
if deleteVHD {
|
||||
requestURL += "?comp=media"
|
||||
}
|
||||
|
||||
return c.client.SendAzureDeleteRequest(requestURL)
|
||||
}
|
||||
|
||||
// DeleteDisk deletes the specified data or operating system disk from the image
|
||||
// repository that is associated with the specified subscription
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/jj157200.aspx
|
||||
func (c DiskClient) DeleteDisk(name string, deleteVHD bool) error {
|
||||
if name == "" {
|
||||
return fmt.Errorf(errParamNotSpecified, "name")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(deleteDiskURL, name)
|
||||
if deleteVHD {
|
||||
requestURL += "?comp=media"
|
||||
}
|
||||
|
||||
_, err := c.client.SendAzureDeleteRequest(requestURL) // request is handled synchronously
|
||||
return err
|
||||
}
|
||||
|
||||
// GetDataDisk retrieves the specified data disk from a Virtual Machine
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/jj157180.aspx
|
||||
func (c DiskClient) GetDataDisk(
|
||||
service string,
|
||||
deployment string,
|
||||
role string,
|
||||
lun int) (DataDiskResponse, error) {
|
||||
var response DataDiskResponse
|
||||
if service == "" {
|
||||
return response, fmt.Errorf(errParamNotSpecified, "service")
|
||||
}
|
||||
if deployment == "" {
|
||||
return response, fmt.Errorf(errParamNotSpecified, "deployment")
|
||||
}
|
||||
if role == "" {
|
||||
return response, fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(getDataDiskURL, service, deployment, role, lun)
|
||||
|
||||
data, err := c.client.SendAzureGetRequest(requestURL)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(data, &response)
|
||||
return response, err
|
||||
}
|
||||
|
||||
// GetDisk retrieves information about the specified disk
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dn775053.aspx
|
||||
func (c DiskClient) GetDisk(name string) (DiskResponse, error) {
|
||||
var response DiskResponse
|
||||
if name == "" {
|
||||
return response, fmt.Errorf(errParamNotSpecified, "name")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(getDiskURL, name)
|
||||
|
||||
data, err := c.client.SendAzureGetRequest(requestURL)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(data, &response)
|
||||
return response, err
|
||||
}
|
||||
|
||||
// ListDisks retrieves a list of the disks in the image repository that is associated
|
||||
// with the specified subscription
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/jj157176.aspx
|
||||
func (c DiskClient) ListDisks() (ListDiskResponse, error) {
|
||||
var response ListDiskResponse
|
||||
|
||||
data, err := c.client.SendAzureGetRequest(listDisksURL)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(data, &response)
|
||||
return response, err
|
||||
}
|
||||
|
||||
// UpdateDataDisk updates the configuration of the specified data disk that is
|
||||
// attached to the specified Virtual Machine
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/jj157190.aspx
|
||||
func (c DiskClient) UpdateDataDisk(
|
||||
service string,
|
||||
deployment string,
|
||||
role string,
|
||||
lun int,
|
||||
params UpdateDataDiskParameters) (management.OperationID, error) {
|
||||
if service == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "service")
|
||||
}
|
||||
if deployment == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "deployment")
|
||||
}
|
||||
if role == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(updateDataDiskURL, service, deployment, role, lun)
|
||||
|
||||
req, err := xml.Marshal(params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return c.client.SendAzurePutRequest(requestURL, "", req)
|
||||
}
|
||||
|
||||
// UpdateDisk updates the label of an existing disk in the image repository that is
|
||||
// associated with the specified subscription
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/jj157205.aspx
|
||||
func (c DiskClient) UpdateDisk(
|
||||
name string,
|
||||
params UpdateDiskParameters) (management.OperationID, error) {
|
||||
if name == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "name")
|
||||
}
|
||||
|
||||
requestURL := fmt.Sprintf(updateDiskURL, name)
|
||||
|
||||
req, err := xml.Marshal(params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return c.client.SendAzurePutRequest(requestURL, "", req)
|
||||
}
|
||||
Generated
Vendored
+134
@@ -0,0 +1,134 @@
|
||||
package virtualmachinedisk
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
// DiskClient is used to perform operations on Azure Disks
|
||||
type DiskClient struct {
|
||||
client management.Client
|
||||
}
|
||||
|
||||
// CreateDiskParameters represents a disk
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/jj157188.aspx
|
||||
type CreateDiskParameters struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure Disk"`
|
||||
OS OperatingSystemType `xml:",omitempty"`
|
||||
Label string
|
||||
MediaLink string `xml:",omitempty"`
|
||||
Name string
|
||||
}
|
||||
|
||||
// UpdateDiskParameters represents a disk
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/jj157188.aspx
|
||||
type UpdateDiskParameters struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure Disk"`
|
||||
Label string `xml:",omitempty"`
|
||||
Name string
|
||||
ResizedSizeInGB int `xml:",omitempty"`
|
||||
}
|
||||
|
||||
// ListDiskResponse represents a disk
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/jj157188.aspx
|
||||
type ListDiskResponse struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure Disks"`
|
||||
Disk []DiskResponse
|
||||
}
|
||||
|
||||
// DiskResponse represents a disk
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/jj157188.aspx
|
||||
type DiskResponse struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure Disk"`
|
||||
AffinityGroup string
|
||||
AttachedTo Resource
|
||||
IsCorrupted bool
|
||||
OS OperatingSystemType
|
||||
Location string
|
||||
LogicalDiskSizeInGB int
|
||||
MediaLink string
|
||||
Name string
|
||||
SourceImageName string
|
||||
CreatedTime string
|
||||
IOType IOType
|
||||
}
|
||||
|
||||
// Resource describes the resource details a disk is currently attached to
|
||||
type Resource struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure AttachedTo"`
|
||||
DeploymentName string
|
||||
HostedServiceName string
|
||||
RoleName string
|
||||
}
|
||||
|
||||
// IOType represents an IO type
|
||||
type IOType string
|
||||
|
||||
// These constants represent the possible IO types
|
||||
const (
|
||||
IOTypeProvisioned IOType = "Provisioned"
|
||||
IOTypeStandard IOType = "Standard"
|
||||
)
|
||||
|
||||
// OperatingSystemType represents an operating system type
|
||||
type OperatingSystemType string
|
||||
|
||||
// These constants represent the valid operating system types
|
||||
const (
|
||||
OperatingSystemTypeNull OperatingSystemType = "NULL"
|
||||
OperatingSystemTypeLinux OperatingSystemType = "Linux"
|
||||
OperatingSystemTypeWindows OperatingSystemType = "Windows"
|
||||
)
|
||||
|
||||
// CreateDataDiskParameters represents a data disk
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/jj157188.aspx
|
||||
type CreateDataDiskParameters struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure DataVirtualHardDisk"`
|
||||
HostCaching HostCachingType `xml:",omitempty"`
|
||||
DiskLabel string `xml:",omitempty"`
|
||||
DiskName string `xml:",omitempty"`
|
||||
Lun int `xml:",omitempty"`
|
||||
LogicalDiskSizeInGB int `xml:",omitempty"`
|
||||
MediaLink string
|
||||
SourceMediaLink string `xml:",omitempty"`
|
||||
}
|
||||
|
||||
// UpdateDataDiskParameters represents a data disk
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/jj157188.aspx
|
||||
type UpdateDataDiskParameters struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure DataVirtualHardDisk"`
|
||||
HostCaching HostCachingType `xml:",omitempty"`
|
||||
DiskName string
|
||||
Lun int
|
||||
MediaLink string
|
||||
}
|
||||
|
||||
// DataDiskResponse represents a data disk
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/azure/jj157188.aspx
|
||||
type DataDiskResponse struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure DataVirtualHardDisk"`
|
||||
HostCaching HostCachingType
|
||||
DiskLabel string
|
||||
DiskName string
|
||||
Lun int
|
||||
LogicalDiskSizeInGB int
|
||||
MediaLink string
|
||||
}
|
||||
|
||||
// HostCachingType represents a host caching type
|
||||
type HostCachingType string
|
||||
|
||||
// These constants represent the valid host caching types
|
||||
const (
|
||||
HostCachingTypeNone HostCachingType = "None"
|
||||
HostCachingTypeReadOnly HostCachingType = "ReadOnly"
|
||||
HostCachingTypeReadWrite HostCachingType = "ReadWrite"
|
||||
)
|
||||
Generated
Vendored
+110
@@ -0,0 +1,110 @@
|
||||
// Package virtualmachineimage provides a client for Virtual Machine Images.
|
||||
package virtualmachineimage
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
const (
|
||||
azureImageListURL = "services/vmimages"
|
||||
azureImageDeleteURLformat = "services/vmimages/%s"
|
||||
azureRoleOperationsURL = "services/hostedservices/%s/deployments/%s/roleinstances/%s/operations"
|
||||
errParamNotSpecified = "Parameter %s is not specified."
|
||||
)
|
||||
|
||||
//NewClient is used to instantiate a new Client from an Azure client
|
||||
func NewClient(client management.Client) Client {
|
||||
return Client{client}
|
||||
}
|
||||
|
||||
//ListVirtualMachineImages lists the available VM images, filtered by the optional parameters.
|
||||
//See https://msdn.microsoft.com/en-us/library/azure/dn499770.aspx
|
||||
func (c Client) ListVirtualMachineImages(parameters ListParameters) (ListVirtualMachineImagesResponse, error) {
|
||||
var imageList ListVirtualMachineImagesResponse
|
||||
|
||||
listURL := azureImageListURL
|
||||
|
||||
v := url.Values{}
|
||||
if parameters.Location != "" {
|
||||
v.Add("location", parameters.Location)
|
||||
}
|
||||
|
||||
if parameters.Publisher != "" {
|
||||
v.Add("publisher", parameters.Publisher)
|
||||
}
|
||||
|
||||
if parameters.Category != "" {
|
||||
v.Add("category", parameters.Category)
|
||||
}
|
||||
|
||||
query := v.Encode()
|
||||
if query != "" {
|
||||
listURL = listURL + "?" + query
|
||||
}
|
||||
|
||||
response, err := c.SendAzureGetRequest(listURL)
|
||||
if err != nil {
|
||||
return imageList, err
|
||||
}
|
||||
err = xml.Unmarshal(response, &imageList)
|
||||
return imageList, err
|
||||
}
|
||||
|
||||
//DeleteVirtualMachineImage deletes the named VM image. If deleteVHDs is specified,
|
||||
//the referenced OS and data disks are also deleted.
|
||||
//See https://msdn.microsoft.com/en-us/library/azure/dn499769.aspx
|
||||
func (c Client) DeleteVirtualMachineImage(name string, deleteVHDs bool) error {
|
||||
if name == "" {
|
||||
return fmt.Errorf(errParamNotSpecified, "name")
|
||||
}
|
||||
|
||||
uri := fmt.Sprintf(azureImageDeleteURLformat, name)
|
||||
|
||||
if deleteVHDs {
|
||||
uri = uri + "?comp=media"
|
||||
}
|
||||
|
||||
_, err := c.SendAzureDeleteRequest(uri) // delete is synchronous for this operation
|
||||
return err
|
||||
}
|
||||
|
||||
type ListParameters struct {
|
||||
Location string
|
||||
Publisher string
|
||||
Category string
|
||||
}
|
||||
|
||||
const CategoryUser = "User"
|
||||
|
||||
//Capture captures a VM into a VM image. The VM has to be shut down previously.
|
||||
//See https://msdn.microsoft.com/en-us/library/azure/dn499768.aspx
|
||||
func (c Client) Capture(cloudServiceName, deploymentName, roleName string,
|
||||
name, label string, osState OSState, parameters CaptureParameters) (management.OperationID, error) {
|
||||
if cloudServiceName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
|
||||
}
|
||||
if deploymentName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
|
||||
}
|
||||
if roleName == "" {
|
||||
return "", fmt.Errorf(errParamNotSpecified, "roleName")
|
||||
}
|
||||
|
||||
request := CaptureRoleAsVMImageOperation{
|
||||
VMImageName: name,
|
||||
VMImageLabel: label,
|
||||
OSState: osState,
|
||||
CaptureParameters: parameters,
|
||||
}
|
||||
data, err := xml.Marshal(request)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return c.SendAzurePostRequest(fmt.Sprintf(azureRoleOperationsURL,
|
||||
cloudServiceName, deploymentName, roleName), data)
|
||||
}
|
||||
Generated
Vendored
+95
@@ -0,0 +1,95 @@
|
||||
package virtualmachineimage
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
vmdisk "github.com/Azure/azure-sdk-for-go/management/virtualmachinedisk"
|
||||
)
|
||||
|
||||
// Client is used to perform operations on Azure VM Images.
|
||||
type Client struct {
|
||||
management.Client
|
||||
}
|
||||
|
||||
type ListVirtualMachineImagesResponse struct {
|
||||
VMImages []VMImage `xml:"VMImage"`
|
||||
}
|
||||
|
||||
type VMImage struct {
|
||||
Name string // Specifies the name of the image.
|
||||
Label string // Specifies an identifier for the image.
|
||||
Category string // Specifies the repository classification of the image. All user images have the category User.
|
||||
Description string // Specifies the description of the image.
|
||||
OSDiskConfiguration OSDiskConfiguration // Specifies configuration information for the operating system disk that is associated with the image.
|
||||
DataDiskConfigurations []DataDiskConfiguration `xml:">DataDiskConfiguration"` // Specifies configuration information for the data disks that are associated with the image. A VM Image might not have data disks associated with it.
|
||||
ServiceName string // Specifies the name of the cloud service that contained the Virtual Machine from which the image was created.
|
||||
DeploymentName string // Specifies the name of the deployment that contained the Virtual Machine from which the image was created.
|
||||
RoleName string // Specifies the name of the Virtual Machine from which the image was created.
|
||||
Location string // Specifies the geo-location in which the media is located. The Location value is derived from the storage account that contains the blob in which the media is located. If the storage account belongs to an affinity group the value is NULL and the element is not displayed in the response.
|
||||
AffinityGroup string // Specifies the affinity group in which the media is located. The AffinityGroup value is derived from the storage account that contains the blob in which the media is located. If the storage account does not belong to an affinity group the value is NULL and the element is not displayed in the response.
|
||||
CreatedTime string // Specifies the time that the image was created.
|
||||
ModifiedTime string // Specifies the time that the image was last updated.
|
||||
Language string // Specifies the language of the image.
|
||||
ImageFamily string // Specifies a value that can be used to group VM Images.
|
||||
RecommendedVMSize string // Optional. Specifies the size to use for the Virtual Machine that is created from the VM Image.
|
||||
IsPremium string // Indicates whether the image contains software or associated services that will incur charges above the core price for the virtual machine. For additional details, see the PricingDetailLink element.
|
||||
Eula string // Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA.
|
||||
IconURI string `xml:"IconUri"` // Specifies the URI to the icon that is displayed for the image in the Management Portal.
|
||||
SmallIconURI string `xml:"SmallIconUri"` // Specifies the URI to the small icon that is displayed for the image in the Management Portal.
|
||||
PrivacyURI string `xml:"PrivacyUri"` // Specifies the URI that points to a document that contains the privacy policy related to the image.
|
||||
PublishedDate string // Specifies the date when the image was added to the image repository.
|
||||
}
|
||||
|
||||
type OSState string
|
||||
|
||||
const (
|
||||
OSStateGeneralized OSState = "Generalized"
|
||||
OSStateSpecialized OSState = "Specialized"
|
||||
)
|
||||
|
||||
type IOType string
|
||||
|
||||
const (
|
||||
IOTypeProvisioned IOType = "Provisioned"
|
||||
IOTypeStandard IOType = "Standard"
|
||||
)
|
||||
|
||||
// OSDiskConfiguration specifies configuration information for the operating
|
||||
// system disk that is associated with the image.
|
||||
type OSDiskConfiguration struct {
|
||||
Name string // Specifies the name of the operating system disk.
|
||||
HostCaching vmdisk.HostCachingType // Specifies the caching behavior of the operating system disk.
|
||||
OSState OSState // Specifies the state of the operating system in the image.
|
||||
OS string // Specifies the operating system type of the image.
|
||||
MediaLink string // Specifies the location of the blob in Azure storage. The blob location belongs to a storage account in the subscription specified by the <subscription-id> value in the operation call.
|
||||
LogicalSizeInGB float64 // Specifies the size, in GB, of the operating system disk.
|
||||
IOType IOType // Identifies the type of the storage account for the backing VHD. If the backing VHD is in an Provisioned Storage account, “Provisioned” is returned otherwise “Standard” is returned.
|
||||
}
|
||||
|
||||
// DataDiskConfiguration specifies configuration information for the data disks
|
||||
// that are associated with the image.
|
||||
type DataDiskConfiguration struct {
|
||||
Name string // Specifies the name of the data disk.
|
||||
HostCaching vmdisk.HostCachingType // Specifies the caching behavior of the data disk.
|
||||
Lun string // Specifies the Logical Unit Number (LUN) for the data disk.
|
||||
MediaLink string // Specifies the location of the blob in Azure storage. The blob location belongs to a storage account in the subscription specified by the <subscription-id> value in the operation call.
|
||||
LogicalSizeInGB float64 // Specifies the size, in GB, of the data disk.
|
||||
IOType IOType // Identifies the type of the storage account for the backing VHD. If the backing VHD is in an Provisioned Storage account, “Provisioned” is returned otherwise “Standard” is returned.
|
||||
}
|
||||
|
||||
type CaptureRoleAsVMImageOperation struct {
|
||||
XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure CaptureRoleAsVMImageOperation"`
|
||||
OperationType string //CaptureRoleAsVMImageOperation
|
||||
OSState OSState
|
||||
VMImageName string
|
||||
VMImageLabel string
|
||||
CaptureParameters
|
||||
}
|
||||
|
||||
type CaptureParameters struct {
|
||||
Description string `xml:",omitempty"`
|
||||
Language string `xml:",omitempty"`
|
||||
ImageFamily string `xml:",omitempty"`
|
||||
RecommendedVMSize string `xml:",omitempty"`
|
||||
}
|
||||
Generated
Vendored
+110
@@ -0,0 +1,110 @@
|
||||
package virtualmachineimage
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const xml1 = `
|
||||
<VMImage>
|
||||
<Name>imgName</Name>
|
||||
<Label>PackerMade_Ubuntu_Serv14</Label>
|
||||
<Category>User</Category>
|
||||
<Description>packer made image</Description>
|
||||
<OSDiskConfiguration>
|
||||
<Name>OSDisk</Name>
|
||||
<HostCaching>ReadWrite</HostCaching>
|
||||
<OSState>Generalized</OSState>
|
||||
<OS>Linux</OS>
|
||||
<MediaLink>https://sa.blob.core.windows.net/images/PackerMade_Ubuntu_Serv14_2015-12-12.vhd</MediaLink>
|
||||
<LogicalDiskSizeInGB>30</LogicalDiskSizeInGB>
|
||||
<IOType>Standard</IOType>
|
||||
</OSDiskConfiguration>
|
||||
<DataDiskConfigurations/>
|
||||
<ServiceName>PkrSrvf3mz03u4mi</ServiceName>
|
||||
<DeploymentName>PkrVMf3mz03u4mi</DeploymentName>
|
||||
<RoleName>PkrVMf3mz03u4mi</RoleName>
|
||||
<Location>Central US</Location>
|
||||
<CreatedTime>2015-12-12T08:59:29.1936858Z</CreatedTime>
|
||||
<ModifiedTime>2015-12-12T08:59:29.1936858Z</ModifiedTime>
|
||||
<ImageFamily>PackerMade</ImageFamily>
|
||||
<RecommendedVMSize>Small</RecommendedVMSize>
|
||||
<IsPremium>false</IsPremium>
|
||||
<VMImageState>VMImageReadyForUse</VMImageState>
|
||||
<RoleStateOnCapture>StoppedVM</RoleStateOnCapture>
|
||||
<RoleSizeOnCapture>Small</RoleSizeOnCapture>
|
||||
</VMImage>`
|
||||
const xml2 = `
|
||||
<VMImage>
|
||||
<Name>imgName</Name>
|
||||
<Label>PackerMade_Ubuntu_Serv14</Label>
|
||||
<Category>User</Category>
|
||||
<Description>packer made image</Description>
|
||||
<OSDiskConfiguration>
|
||||
<Name>OSDisk</Name>
|
||||
<HostCaching>ReadWrite</HostCaching>
|
||||
<OSState>Generalized</OSState>
|
||||
<OS>Linux</OS>
|
||||
<MediaLink>https://sa.blob.core.windows.net/images/PackerMade_Ubuntu_Serv14_2015-12-12.vhd</MediaLink>
|
||||
<LogicalDiskSizeInGB>30</LogicalDiskSizeInGB>
|
||||
<IOType>Standard</IOType>
|
||||
</OSDiskConfiguration>
|
||||
<DataDiskConfigurations>
|
||||
<DataDiskConfiguration>
|
||||
<Name>DataDisk1</Name>
|
||||
<HostCaching>ReadWrite</HostCaching>
|
||||
<MediaLink>https://sa.blob.core.windows.net/images/PackerMade_Ubuntu_Serv14_2015-12-12-dd1.vhd</MediaLink>
|
||||
<LogicalDiskSizeInGB>31</LogicalDiskSizeInGB>
|
||||
<IOType>Standard</IOType>
|
||||
</DataDiskConfiguration>
|
||||
<DataDiskConfiguration>
|
||||
<Name>DataDisk2</Name>
|
||||
<HostCaching>ReadWrite</HostCaching>
|
||||
<MediaLink>https://sa.blob.core.windows.net/images/PackerMade_Ubuntu_Serv14_2015-12-12-dd2.vhd</MediaLink>
|
||||
<LogicalDiskSizeInGB>32</LogicalDiskSizeInGB>
|
||||
<IOType>Standard</IOType>
|
||||
</DataDiskConfiguration>
|
||||
</DataDiskConfigurations>
|
||||
<ServiceName>PkrSrvf3mz03u4mi</ServiceName>
|
||||
<DeploymentName>PkrVMf3mz03u4mi</DeploymentName>
|
||||
<RoleName>PkrVMf3mz03u4mi</RoleName>
|
||||
<Location>Central US</Location>
|
||||
<CreatedTime>2015-12-12T08:59:29.1936858Z</CreatedTime>
|
||||
<ModifiedTime>2015-12-12T08:59:29.1936858Z</ModifiedTime>
|
||||
<ImageFamily>PackerMade</ImageFamily>
|
||||
<RecommendedVMSize>Small</RecommendedVMSize>
|
||||
<IsPremium>false</IsPremium>
|
||||
<VMImageState>VMImageReadyForUse</VMImageState>
|
||||
<RoleStateOnCapture>StoppedVM</RoleStateOnCapture>
|
||||
<RoleSizeOnCapture>Small</RoleSizeOnCapture>
|
||||
</VMImage>`
|
||||
|
||||
func Test_NoDataDisksUnmarshal(t *testing.T) {
|
||||
var image VMImage
|
||||
if err := xml.Unmarshal([]byte(xml1), &image); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
check := checker{t}
|
||||
check.Equal(0, len(image.DataDiskConfigurations))
|
||||
}
|
||||
|
||||
func Test_DataDiskCountUnmarshal(t *testing.T) {
|
||||
var image VMImage
|
||||
if err := xml.Unmarshal([]byte(xml2), &image); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
check := checker{t}
|
||||
check.Equal(2, len(image.DataDiskConfigurations))
|
||||
check.Equal("DataDisk1", image.DataDiskConfigurations[0].Name)
|
||||
check.Equal("DataDisk2", image.DataDiskConfigurations[1].Name)
|
||||
}
|
||||
|
||||
type checker struct{ *testing.T }
|
||||
|
||||
func (a *checker) Equal(expected, actual interface{}) {
|
||||
if expected != actual {
|
||||
a.T.Fatalf("Expected %q, but got %q", expected, actual)
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
// Package virtualnetwork provides a client for Virtual Networks.
|
||||
package virtualnetwork
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
const (
|
||||
azureNetworkConfigurationURL = "services/networking/media"
|
||||
)
|
||||
|
||||
// NewClient is used to return new VirtualNetworkClient instance
|
||||
func NewClient(client management.Client) VirtualNetworkClient {
|
||||
return VirtualNetworkClient{client: client}
|
||||
}
|
||||
|
||||
// GetVirtualNetworkConfiguration retreives the current virtual network
|
||||
// configuration for the currently active subscription. Note that the
|
||||
// underlying Azure API means that network related operations are not safe
|
||||
// for running concurrently.
|
||||
func (c VirtualNetworkClient) GetVirtualNetworkConfiguration() (NetworkConfiguration, error) {
|
||||
networkConfiguration := c.NewNetworkConfiguration()
|
||||
response, err := c.client.SendAzureGetRequest(azureNetworkConfigurationURL)
|
||||
if err != nil {
|
||||
return networkConfiguration, err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(response, &networkConfiguration)
|
||||
return networkConfiguration, err
|
||||
|
||||
}
|
||||
|
||||
// SetVirtualNetworkConfiguration configures the virtual networks for the
|
||||
// currently active subscription according to the NetworkConfiguration given.
|
||||
// Note that the underlying Azure API means that network related operations
|
||||
// are not safe for running concurrently.
|
||||
func (c VirtualNetworkClient) SetVirtualNetworkConfiguration(networkConfiguration NetworkConfiguration) (management.OperationID, error) {
|
||||
networkConfiguration.setXMLNamespaces()
|
||||
networkConfigurationBytes, err := xml.Marshal(networkConfiguration)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return c.client.SendAzurePutRequest(azureNetworkConfigurationURL, "text/plain", networkConfigurationBytes)
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
package virtualnetwork
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
const xmlNamespace = "http://schemas.microsoft.com/ServiceHosting/2011/07/NetworkConfiguration"
|
||||
const xmlNamespaceXsd = "http://www.w3.org/2001/XMLSchema"
|
||||
const xmlNamespaceXsi = "http://www.w3.org/2001/XMLSchema-instance"
|
||||
|
||||
// VirtualNetworkClient is used to perform operations on Virtual Networks.
|
||||
type VirtualNetworkClient struct {
|
||||
client management.Client
|
||||
}
|
||||
|
||||
// NetworkConfiguration represents the network configuration for an entire Azure
|
||||
// subscription.
|
||||
type NetworkConfiguration struct {
|
||||
XMLName xml.Name `xml:"NetworkConfiguration"`
|
||||
XMLNamespaceXsd string `xml:"xmlns:xsd,attr"`
|
||||
XMLNamespaceXsi string `xml:"xmlns:xsi,attr"`
|
||||
XMLNs string `xml:"xmlns,attr"`
|
||||
Configuration VirtualNetworkConfiguration `xml:"VirtualNetworkConfiguration"`
|
||||
|
||||
// TODO: Nicer builder methods for these that abstract away the
|
||||
// underlying structure.
|
||||
}
|
||||
|
||||
// NewNetworkConfiguration creates a new empty NetworkConfiguration structure
|
||||
// for further configuration. The XML namespaces are already set correctly.
|
||||
func (client *VirtualNetworkClient) NewNetworkConfiguration() NetworkConfiguration {
|
||||
networkConfiguration := NetworkConfiguration{}
|
||||
networkConfiguration.setXMLNamespaces()
|
||||
return networkConfiguration
|
||||
}
|
||||
|
||||
// setXMLNamespaces ensure that all of the required namespaces are set. It
|
||||
// should be called prior to marshalling the structure to XML for use with the
|
||||
// Azure REST endpoint. It is used internally prior to submitting requests, but
|
||||
// since it is idempotent there is no harm in repeat calls.
|
||||
func (n *NetworkConfiguration) setXMLNamespaces() {
|
||||
n.XMLNamespaceXsd = xmlNamespaceXsd
|
||||
n.XMLNamespaceXsi = xmlNamespaceXsi
|
||||
n.XMLNs = xmlNamespace
|
||||
}
|
||||
|
||||
type VirtualNetworkConfiguration struct {
|
||||
DNS DNS `xml:"Dns,omitempty"`
|
||||
LocalNetworkSites []LocalNetworkSite `xml:"LocalNetworkSites>LocalNetworkSite"`
|
||||
VirtualNetworkSites []VirtualNetworkSite `xml:"VirtualNetworkSites>VirtualNetworkSite"`
|
||||
}
|
||||
|
||||
type DNS struct {
|
||||
DNSServers []DNSServer `xml:"DnsServers>DnsServer,omitempty"`
|
||||
}
|
||||
|
||||
type DNSServer struct {
|
||||
XMLName xml.Name `xml:"DnsServer"`
|
||||
Name string `xml:"name,attr"`
|
||||
IPAddress string `xml:"IPAddress,attr"`
|
||||
}
|
||||
|
||||
type DNSServerRef struct {
|
||||
Name string `xml:"name,attr"`
|
||||
}
|
||||
|
||||
type VirtualNetworkSite struct {
|
||||
Name string `xml:"name,attr"`
|
||||
Location string `xml:"Location,attr"`
|
||||
AddressSpace AddressSpace `xml:"AddressSpace"`
|
||||
Subnets []Subnet `xml:"Subnets>Subnet"`
|
||||
DNSServersRef []DNSServerRef `xml:"DnsServersRef>DnsServerRef,omitempty"`
|
||||
}
|
||||
|
||||
type LocalNetworkSite struct {
|
||||
Name string `xml:"name,attr"`
|
||||
VPNGatewayAddress string
|
||||
AddressSpace AddressSpace
|
||||
}
|
||||
|
||||
type AddressSpace struct {
|
||||
AddressPrefix []string
|
||||
}
|
||||
|
||||
type Subnet struct {
|
||||
Name string `xml:"name,attr"`
|
||||
AddressPrefix string
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package vmutils
|
||||
|
||||
import (
|
||||
vm "github.com/Azure/azure-sdk-for-go/management/virtualmachine"
|
||||
)
|
||||
|
||||
func updateOrAddConfig(configs []vm.ConfigurationSet, configType vm.ConfigurationSetType, update func(*vm.ConfigurationSet)) []vm.ConfigurationSet {
|
||||
config := findConfig(configs, configType)
|
||||
if config == nil {
|
||||
configs = append(configs, vm.ConfigurationSet{ConfigurationSetType: configType})
|
||||
config = findConfig(configs, configType)
|
||||
}
|
||||
update(config)
|
||||
|
||||
return configs
|
||||
}
|
||||
|
||||
func findConfig(configs []vm.ConfigurationSet, configType vm.ConfigurationSetType) *vm.ConfigurationSet {
|
||||
for i, config := range configs {
|
||||
if config.ConfigurationSetType == configType {
|
||||
// need to return a pointer to the original set in configs,
|
||||
// not the copy made by the range iterator
|
||||
return &configs[i]
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package vmutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
vm "github.com/Azure/azure-sdk-for-go/management/virtualmachine"
|
||||
vmdisk "github.com/Azure/azure-sdk-for-go/management/virtualmachinedisk"
|
||||
)
|
||||
|
||||
// ConfigureWithNewDataDisk adds configuration for a new (empty) data disk
|
||||
func ConfigureWithNewDataDisk(role *vm.Role, label, destinationVhdStorageURL string, sizeInGB int, cachingType vmdisk.HostCachingType) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
appendDataDisk(role, vm.DataVirtualHardDisk{
|
||||
DiskLabel: label,
|
||||
HostCaching: cachingType,
|
||||
LogicalDiskSizeInGB: sizeInGB,
|
||||
MediaLink: destinationVhdStorageURL,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConfigureWithExistingDataDisk adds configuration for an existing data disk
|
||||
func ConfigureWithExistingDataDisk(role *vm.Role, diskName string, cachingType vmdisk.HostCachingType) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
appendDataDisk(role, vm.DataVirtualHardDisk{
|
||||
DiskName: diskName,
|
||||
HostCaching: cachingType,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConfigureWithVhdDataDisk adds configuration for adding a vhd in a storage
|
||||
// account as a data disk
|
||||
func ConfigureWithVhdDataDisk(role *vm.Role, sourceVhdStorageURL string, cachingType vmdisk.HostCachingType) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
appendDataDisk(role, vm.DataVirtualHardDisk{
|
||||
SourceMediaLink: sourceVhdStorageURL,
|
||||
HostCaching: cachingType,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func appendDataDisk(role *vm.Role, disk vm.DataVirtualHardDisk) {
|
||||
disk.Lun = len(role.DataVirtualHardDisks)
|
||||
role.DataVirtualHardDisks = append(role.DataVirtualHardDisks, disk)
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
package vmutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
vm "github.com/Azure/azure-sdk-for-go/management/virtualmachine"
|
||||
)
|
||||
|
||||
// ConfigureDeploymentFromRemoteImage configures VM Role to deploy from a remote
|
||||
// image source. "remoteImageSourceURL" can be any publically accessible URL to
|
||||
// a VHD file, including but not limited to a SAS Azure Storage blob url. "os"
|
||||
// needs to be either "Linux" or "Windows". "label" is optional.
|
||||
func ConfigureDeploymentFromRemoteImage(
|
||||
role *vm.Role,
|
||||
remoteImageSourceURL string,
|
||||
os string,
|
||||
newDiskName string,
|
||||
destinationVhdStorageURL string,
|
||||
label string) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
role.OSVirtualHardDisk = &vm.OSVirtualHardDisk{
|
||||
RemoteSourceImageLink: remoteImageSourceURL,
|
||||
MediaLink: destinationVhdStorageURL,
|
||||
DiskName: newDiskName,
|
||||
OS: os,
|
||||
DiskLabel: label,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConfigureDeploymentFromPlatformImage configures VM Role to deploy from a
|
||||
// platform image. See osimage package for methods to retrieve a list of the
|
||||
// available platform images. "label" is optional.
|
||||
func ConfigureDeploymentFromPlatformImage(
|
||||
role *vm.Role,
|
||||
imageName string,
|
||||
mediaLink string,
|
||||
label string) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
role.OSVirtualHardDisk = &vm.OSVirtualHardDisk{
|
||||
SourceImageName: imageName,
|
||||
MediaLink: mediaLink,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConfigureDeploymentFromPublishedVMImage configures VM Role to deploy from
|
||||
// a published (public) VM image.
|
||||
func ConfigureDeploymentFromPublishedVMImage(
|
||||
role *vm.Role,
|
||||
vmImageName string,
|
||||
mediaLocation string,
|
||||
provisionGuestAgent bool) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
role.VMImageName = vmImageName
|
||||
role.MediaLocation = mediaLocation
|
||||
role.ProvisionGuestAgent = provisionGuestAgent
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConfigureDeploymentFromUserVMImage configures VM Role to deploy from a previously
|
||||
// captured (user generated) VM image.
|
||||
func ConfigureDeploymentFromUserVMImage(
|
||||
role *vm.Role,
|
||||
vmImageName string) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
role.VMImageName = vmImageName
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConfigureDeploymentFromExistingOSDisk configures VM Role to deploy from an
|
||||
// existing disk. 'label' is optional.
|
||||
func ConfigureDeploymentFromExistingOSDisk(role *vm.Role, osDiskName, label string) error {
|
||||
role.OSVirtualHardDisk = &vm.OSVirtualHardDisk{
|
||||
DiskName: osDiskName,
|
||||
DiskLabel: label,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
package vmutils
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
vm "github.com/Azure/azure-sdk-for-go/management/virtualmachine"
|
||||
)
|
||||
|
||||
const (
|
||||
dockerPublicConfigVersion = 2
|
||||
)
|
||||
|
||||
func AddAzureVMExtensionConfiguration(role *vm.Role, name, publisher, version, referenceName, state string,
|
||||
publicConfigurationValue, privateConfigurationValue []byte) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
extension := vm.ResourceExtensionReference{
|
||||
Name: name,
|
||||
Publisher: publisher,
|
||||
Version: version,
|
||||
ReferenceName: referenceName,
|
||||
State: state,
|
||||
}
|
||||
|
||||
if len(privateConfigurationValue) != 0 {
|
||||
extension.ParameterValues = append(extension.ParameterValues, vm.ResourceExtensionParameter{
|
||||
Key: "ignored",
|
||||
Value: base64.StdEncoding.EncodeToString(privateConfigurationValue),
|
||||
Type: "Private",
|
||||
})
|
||||
}
|
||||
|
||||
if len(publicConfigurationValue) != 0 {
|
||||
extension.ParameterValues = append(extension.ParameterValues, vm.ResourceExtensionParameter{
|
||||
Key: "ignored",
|
||||
Value: base64.StdEncoding.EncodeToString(publicConfigurationValue),
|
||||
Type: "Public",
|
||||
})
|
||||
}
|
||||
|
||||
if role.ResourceExtensionReferences == nil {
|
||||
role.ResourceExtensionReferences = &[]vm.ResourceExtensionReference{}
|
||||
}
|
||||
extensionList := append(*role.ResourceExtensionReferences, extension)
|
||||
role.ResourceExtensionReferences = &extensionList
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddAzureDockerVMExtensionConfiguration adds the DockerExtension to the role
|
||||
// configuratioon and opens a port "dockerPort"
|
||||
// TODO(ahmetalpbalkan) Deprecate this and move to 'docker-machine' codebase.
|
||||
func AddAzureDockerVMExtensionConfiguration(role *vm.Role, dockerPort int, version string) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
if err := ConfigureWithExternalPort(role, "docker", dockerPort, dockerPort, vm.InputEndpointProtocolTCP); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
publicConfiguration, err := createDockerPublicConfig(dockerPort)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
privateConfiguration, err := json.Marshal(dockerPrivateConfig{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return AddAzureVMExtensionConfiguration(role,
|
||||
"DockerExtension", "MSOpenTech.Extensions",
|
||||
version, "DockerExtension", "enable",
|
||||
publicConfiguration, privateConfiguration)
|
||||
}
|
||||
|
||||
func createDockerPublicConfig(dockerPort int) ([]byte, error) {
|
||||
return json.Marshal(dockerPublicConfig{DockerPort: dockerPort, Version: dockerPublicConfigVersion})
|
||||
}
|
||||
|
||||
type dockerPublicConfig struct {
|
||||
DockerPort int `json:"dockerport"`
|
||||
Version int `json:"version"`
|
||||
}
|
||||
|
||||
type dockerPrivateConfig struct{}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package vmutils
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"testing"
|
||||
|
||||
vm "github.com/Azure/azure-sdk-for-go/management/virtualmachine"
|
||||
)
|
||||
|
||||
func Test_AddAzureVMExtensionConfiguration(t *testing.T) {
|
||||
|
||||
role := vm.Role{}
|
||||
AddAzureVMExtensionConfiguration(&role,
|
||||
"nameOfExtension", "nameOfPublisher", "versionOfExtension", "nameOfReference", "state", []byte{1, 2, 3}, []byte{})
|
||||
|
||||
data, err := xml.MarshalIndent(role, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if expected := `<Role>
|
||||
<ConfigurationSets></ConfigurationSets>
|
||||
<ResourceExtensionReferences>
|
||||
<ResourceExtensionReference>
|
||||
<ReferenceName>nameOfReference</ReferenceName>
|
||||
<Publisher>nameOfPublisher</Publisher>
|
||||
<Name>nameOfExtension</Name>
|
||||
<Version>versionOfExtension</Version>
|
||||
<ResourceExtensionParameterValues>
|
||||
<ResourceExtensionParameterValue>
|
||||
<Key>ignored</Key>
|
||||
<Value>AQID</Value>
|
||||
<Type>Public</Type>
|
||||
</ResourceExtensionParameterValue>
|
||||
</ResourceExtensionParameterValues>
|
||||
<State>state</State>
|
||||
</ResourceExtensionReference>
|
||||
</ResourceExtensionReferences>
|
||||
<DataVirtualHardDisks></DataVirtualHardDisks>
|
||||
</Role>`; string(data) != expected {
|
||||
t.Fatalf("Expected %q, but got %q", expected, string(data))
|
||||
}
|
||||
}
|
||||
+458
@@ -0,0 +1,458 @@
|
||||
package vmutils
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
"github.com/Azure/azure-sdk-for-go/management/hostedservice"
|
||||
"github.com/Azure/azure-sdk-for-go/management/location"
|
||||
"github.com/Azure/azure-sdk-for-go/management/osimage"
|
||||
storage "github.com/Azure/azure-sdk-for-go/management/storageservice"
|
||||
"github.com/Azure/azure-sdk-for-go/management/testutils"
|
||||
vm "github.com/Azure/azure-sdk-for-go/management/virtualmachine"
|
||||
vmimage "github.com/Azure/azure-sdk-for-go/management/virtualmachineimage"
|
||||
)
|
||||
|
||||
func TestDeployPlatformImage(t *testing.T) {
|
||||
client := testutils.GetTestClient(t)
|
||||
vmname := GenerateName()
|
||||
sa := GetTestStorageAccount(t, client)
|
||||
location := sa.StorageServiceProperties.Location
|
||||
|
||||
role := NewVMConfiguration(vmname, "Standard_D3")
|
||||
ConfigureDeploymentFromPlatformImage(&role,
|
||||
GetLinuxTestImage(t, client).Name,
|
||||
fmt.Sprintf("http://%s.blob.core.windows.net/sdktest/%s.vhd", sa.ServiceName, vmname),
|
||||
GenerateName())
|
||||
ConfigureForLinux(&role, "myvm", "azureuser", GeneratePassword())
|
||||
ConfigureWithPublicSSH(&role)
|
||||
|
||||
testRoleConfiguration(t, client, role, location)
|
||||
}
|
||||
|
||||
func TestDeployPlatformWindowsImage(t *testing.T) {
|
||||
client := testutils.GetTestClient(t)
|
||||
vmname := GenerateName()
|
||||
sa := GetTestStorageAccount(t, client)
|
||||
location := sa.StorageServiceProperties.Location
|
||||
|
||||
role := NewVMConfiguration(vmname, "Standard_D3")
|
||||
ConfigureDeploymentFromPlatformImage(&role,
|
||||
GetWindowsTestImage(t, client).Name,
|
||||
fmt.Sprintf("http://%s.blob.core.windows.net/sdktest/%s.vhd", sa.ServiceName, vmname),
|
||||
GenerateName())
|
||||
ConfigureForWindows(&role, vmname, "azureuser", GeneratePassword(), true, "")
|
||||
ConfigureWinRMOverHTTP(&role)
|
||||
ConfigureWinRMOverHTTPS(&role, "")
|
||||
|
||||
testRoleConfiguration(t, client, role, location)
|
||||
}
|
||||
|
||||
func TestVMImageList(t *testing.T) {
|
||||
client := testutils.GetTestClient(t)
|
||||
vmic := vmimage.NewClient(client)
|
||||
il, _ := vmic.ListVirtualMachineImages(vmimage.ListParameters{})
|
||||
for _, im := range il.VMImages {
|
||||
t.Logf("%s -%s", im.Name, im.Description)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeployPlatformOSImageCaptureRedeploy(t *testing.T) {
|
||||
client := testutils.GetTestClient(t)
|
||||
vmname := GenerateName()
|
||||
sa := GetTestStorageAccount(t, client)
|
||||
location := sa.StorageServiceProperties.Location
|
||||
|
||||
role := NewVMConfiguration(vmname, "Standard_D3")
|
||||
ConfigureDeploymentFromPlatformImage(&role,
|
||||
GetLinuxTestImage(t, client).Name,
|
||||
fmt.Sprintf("http://%s.blob.core.windows.net/sdktest/%s.vhd", sa.ServiceName, vmname),
|
||||
GenerateName())
|
||||
ConfigureForLinux(&role, "myvm", "azureuser", GeneratePassword())
|
||||
ConfigureWithPublicSSH(&role)
|
||||
|
||||
t.Logf("Deploying VM: %s", vmname)
|
||||
createRoleConfiguration(t, client, role, location)
|
||||
|
||||
t.Logf("Wait for deployment to enter running state")
|
||||
vmc := vm.NewClient(client)
|
||||
status := vm.DeploymentStatusDeploying
|
||||
for status != vm.DeploymentStatusRunning {
|
||||
deployment, err := vmc.GetDeployment(vmname, vmname)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
break
|
||||
}
|
||||
status = deployment.Status
|
||||
}
|
||||
|
||||
t.Logf("Shutting down VM: %s", vmname)
|
||||
if err := Await(client, func() (management.OperationID, error) {
|
||||
return vmc.ShutdownRole(vmname, vmname, vmname, vm.PostShutdownActionStopped)
|
||||
}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err := WaitForDeploymentPowerState(client, vmname, vmname, vm.PowerStateStopped); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
imagename := GenerateName()
|
||||
t.Logf("Capturing OSImage: %s", imagename)
|
||||
if err := Await(client, func() (management.OperationID, error) {
|
||||
return vmc.CaptureRole(vmname, vmname, vmname, imagename, imagename, nil)
|
||||
}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
im := GetUserOSImage(t, client, imagename)
|
||||
t.Logf("Found image: %+v", im)
|
||||
|
||||
newvmname := GenerateName()
|
||||
role = NewVMConfiguration(newvmname, "Standard_D3")
|
||||
ConfigureDeploymentFromPlatformImage(&role,
|
||||
im.Name,
|
||||
fmt.Sprintf("http://%s.blob.core.windows.net/sdktest/%s.vhd", sa.ServiceName, newvmname),
|
||||
GenerateName())
|
||||
ConfigureForLinux(&role, newvmname, "azureuser", GeneratePassword())
|
||||
ConfigureWithPublicSSH(&role)
|
||||
|
||||
t.Logf("Deploying new VM from freshly captured OS image: %s", newvmname)
|
||||
if err := Await(client, func() (management.OperationID, error) {
|
||||
return vmc.CreateDeployment(role, vmname, vm.CreateDeploymentOptions{})
|
||||
}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
deleteHostedService(t, client, vmname)
|
||||
}
|
||||
|
||||
func TestDeployPlatformVMImageCaptureRedeploy(t *testing.T) {
|
||||
client := testutils.GetTestClient(t)
|
||||
vmname := GenerateName()
|
||||
sa := GetTestStorageAccount(t, client)
|
||||
location := sa.StorageServiceProperties.Location
|
||||
|
||||
role := NewVMConfiguration(vmname, "Standard_D3")
|
||||
ConfigureDeploymentFromPlatformImage(&role,
|
||||
GetLinuxTestImage(t, client).Name,
|
||||
fmt.Sprintf("http://%s.blob.core.windows.net/sdktest/%s.vhd", sa.ServiceName, vmname),
|
||||
GenerateName())
|
||||
ConfigureForLinux(&role, "myvm", "azureuser", GeneratePassword())
|
||||
ConfigureWithPublicSSH(&role)
|
||||
|
||||
t.Logf("Deploying VM: %s", vmname)
|
||||
createRoleConfiguration(t, client, role, location)
|
||||
|
||||
t.Logf("Wait for deployment to enter running state")
|
||||
vmc := vm.NewClient(client)
|
||||
status := vm.DeploymentStatusDeploying
|
||||
for status != vm.DeploymentStatusRunning {
|
||||
deployment, err := vmc.GetDeployment(vmname, vmname)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
break
|
||||
}
|
||||
status = deployment.Status
|
||||
}
|
||||
|
||||
t.Logf("Shutting down VM: %s", vmname)
|
||||
if err := Await(client, func() (management.OperationID, error) {
|
||||
return vmc.ShutdownRole(vmname, vmname, vmname, vm.PostShutdownActionStopped)
|
||||
}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err := WaitForDeploymentInstanceStatus(client, vmname, vmname, vm.InstanceStatusStoppedVM); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
imagename := GenerateName()
|
||||
t.Logf("Capturing VMImage: %s", imagename)
|
||||
if err := Await(client, func() (management.OperationID, error) {
|
||||
return vmimage.NewClient(client).Capture(vmname, vmname, vmname, imagename, imagename, vmimage.OSStateGeneralized, vmimage.CaptureParameters{})
|
||||
}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
im := GetUserVMImage(t, client, imagename)
|
||||
t.Logf("Found image: %+v", im)
|
||||
|
||||
newvmname := GenerateName()
|
||||
role = NewVMConfiguration(newvmname, "Standard_D3")
|
||||
ConfigureDeploymentFromUserVMImage(&role, im.Name)
|
||||
ConfigureForLinux(&role, newvmname, "azureuser", GeneratePassword())
|
||||
ConfigureWithPublicSSH(&role)
|
||||
|
||||
t.Logf("Deploying new VM from freshly captured VM image: %s", newvmname)
|
||||
if err := Await(client, func() (management.OperationID, error) {
|
||||
return vmc.CreateDeployment(role, vmname, vm.CreateDeploymentOptions{})
|
||||
}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
deleteHostedService(t, client, vmname)
|
||||
}
|
||||
|
||||
func TestDeployFromPublishedVmImage(t *testing.T) {
|
||||
client := testutils.GetTestClient(t)
|
||||
vmname := GenerateName()
|
||||
sa := GetTestStorageAccount(t, client)
|
||||
location := sa.StorageServiceProperties.Location
|
||||
|
||||
im := GetVMImage(t, client, func(im vmimage.VMImage) bool {
|
||||
return im.Name ==
|
||||
"fb83b3509582419d99629ce476bcb5c8__SQL-Server-2014-RTM-12.0.2430.0-OLTP-ENU-Win2012R2-cy14su11"
|
||||
})
|
||||
|
||||
role := NewVMConfiguration(vmname, "Standard_D4")
|
||||
ConfigureDeploymentFromPublishedVMImage(&role, im.Name,
|
||||
fmt.Sprintf("http://%s.blob.core.windows.net/%s", sa.ServiceName, vmname), false)
|
||||
ConfigureForWindows(&role, vmname, "azureuser", GeneratePassword(), true, "")
|
||||
ConfigureWithPublicSSH(&role)
|
||||
|
||||
testRoleConfiguration(t, client, role, location)
|
||||
}
|
||||
|
||||
func TestRoleStateOperations(t *testing.T) {
|
||||
client := testutils.GetTestClient(t)
|
||||
vmname := GenerateName()
|
||||
sa := GetTestStorageAccount(t, client)
|
||||
location := sa.StorageServiceProperties.Location
|
||||
|
||||
role := NewVMConfiguration(vmname, "Standard_D3")
|
||||
ConfigureDeploymentFromPlatformImage(&role,
|
||||
GetLinuxTestImage(t, client).Name,
|
||||
fmt.Sprintf("http://%s.blob.core.windows.net/sdktest/%s.vhd", sa.ServiceName, vmname),
|
||||
GenerateName())
|
||||
ConfigureForLinux(&role, "myvm", "azureuser", GeneratePassword())
|
||||
|
||||
createRoleConfiguration(t, client, role, location)
|
||||
|
||||
vmc := vm.NewClient(client)
|
||||
if err := Await(client, func() (management.OperationID, error) {
|
||||
return vmc.ShutdownRole(vmname, vmname, vmname, vm.PostShutdownActionStopped)
|
||||
}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := Await(client, func() (management.OperationID, error) {
|
||||
return vmc.StartRole(vmname, vmname, vmname)
|
||||
}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := Await(client, func() (management.OperationID, error) {
|
||||
return vmc.RestartRole(vmname, vmname, vmname)
|
||||
}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
deleteHostedService(t, client, vmname)
|
||||
}
|
||||
|
||||
func testRoleConfiguration(t *testing.T, client management.Client, role vm.Role, location string) {
|
||||
createRoleConfiguration(t, client, role, location)
|
||||
|
||||
deleteHostedService(t, client, role.RoleName)
|
||||
}
|
||||
|
||||
func createRoleConfiguration(t *testing.T, client management.Client, role vm.Role, location string) {
|
||||
vmc := vm.NewClient(client)
|
||||
hsc := hostedservice.NewClient(client)
|
||||
vmname := role.RoleName
|
||||
|
||||
if err := hsc.CreateHostedService(hostedservice.CreateHostedServiceParameters{
|
||||
ServiceName: vmname, Location: location,
|
||||
Label: base64.StdEncoding.EncodeToString([]byte(vmname))}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err := Await(client, func() (management.OperationID, error) {
|
||||
return vmc.CreateDeployment(role, vmname, vm.CreateDeploymentOptions{})
|
||||
}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func deleteHostedService(t *testing.T, client management.Client, vmname string) {
|
||||
t.Logf("Deleting hosted service: %s", vmname)
|
||||
if err := Await(client, func() (management.OperationID, error) {
|
||||
return hostedservice.NewClient(client).DeleteHostedService(vmname, true)
|
||||
}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// === utility funcs ===
|
||||
|
||||
func GetTestStorageAccount(t *testing.T, client management.Client) storage.StorageServiceResponse {
|
||||
t.Log("Retrieving storage account")
|
||||
sc := storage.NewClient(client)
|
||||
var sa storage.StorageServiceResponse
|
||||
ssl, err := sc.ListStorageServices()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
if len(ssl.StorageServices) == 0 {
|
||||
t.Log("No storage accounts found, creating a new one")
|
||||
lc := location.NewClient(client)
|
||||
ll, err := lc.ListLocations()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
loc := ll.Locations[rnd.Intn(len(ll.Locations))].Name
|
||||
|
||||
t.Logf("Location for new storage account: %s", loc)
|
||||
name := GenerateName()
|
||||
op, err := sc.CreateStorageService(storage.StorageAccountCreateParameters{
|
||||
ServiceName: name,
|
||||
Label: base64.StdEncoding.EncodeToString([]byte(name)),
|
||||
Location: loc,
|
||||
AccountType: storage.AccountTypeStandardLRS})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := client.WaitForOperation(op, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sa, err = sc.GetStorageService(name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
|
||||
sa = ssl.StorageServices[rnd.Intn(len(ssl.StorageServices))]
|
||||
}
|
||||
|
||||
t.Logf("Selected storage account '%s' in location '%s'",
|
||||
sa.ServiceName, sa.StorageServiceProperties.Location)
|
||||
|
||||
return sa
|
||||
}
|
||||
|
||||
func GetLinuxTestImage(t *testing.T, client management.Client) osimage.OSImage {
|
||||
return GetOSImage(t, client, func(im osimage.OSImage) bool {
|
||||
return im.Category == "Public" && im.ImageFamily == "Ubuntu Server 14.04 LTS"
|
||||
})
|
||||
}
|
||||
|
||||
func GetWindowsTestImage(t *testing.T, client management.Client) osimage.OSImage {
|
||||
return GetOSImage(t, client, func(im osimage.OSImage) bool {
|
||||
return im.Category == "Public" && im.ImageFamily == "Windows Server 2012 R2 Datacenter"
|
||||
})
|
||||
}
|
||||
|
||||
func GetUserOSImage(t *testing.T, client management.Client, name string) osimage.OSImage {
|
||||
return GetOSImage(t, client, func(im osimage.OSImage) bool {
|
||||
return im.Category == "User" && im.Name == name
|
||||
})
|
||||
}
|
||||
|
||||
func GetOSImage(
|
||||
t *testing.T,
|
||||
client management.Client,
|
||||
filter func(osimage.OSImage) bool) osimage.OSImage {
|
||||
t.Log("Selecting OS image")
|
||||
osc := osimage.NewClient(client)
|
||||
allimages, err := osc.ListOSImages()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
filtered := []osimage.OSImage{}
|
||||
for _, im := range allimages.OSImages {
|
||||
if filter(im) {
|
||||
filtered = append(filtered, im)
|
||||
}
|
||||
}
|
||||
if len(filtered) == 0 {
|
||||
t.Fatal("Filter too restrictive, no images left?")
|
||||
}
|
||||
|
||||
image := filtered[0]
|
||||
for _, im := range filtered {
|
||||
if im.PublishedDate > image.PublishedDate {
|
||||
image = im
|
||||
}
|
||||
}
|
||||
|
||||
t.Logf("Selecting image '%s'", image.Name)
|
||||
return image
|
||||
}
|
||||
|
||||
func GetUserVMImage(t *testing.T, client management.Client, name string) vmimage.VMImage {
|
||||
return GetVMImage(t, client, func(im vmimage.VMImage) bool {
|
||||
return im.Category == "User" && im.Name == name
|
||||
})
|
||||
}
|
||||
|
||||
func GetVMImage(
|
||||
t *testing.T,
|
||||
client management.Client,
|
||||
filter func(vmimage.VMImage) bool) vmimage.VMImage {
|
||||
t.Log("Selecting VM image")
|
||||
allimages, err := vmimage.NewClient(client).ListVirtualMachineImages(vmimage.ListParameters{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
filtered := []vmimage.VMImage{}
|
||||
for _, im := range allimages.VMImages {
|
||||
if filter(im) {
|
||||
filtered = append(filtered, im)
|
||||
}
|
||||
}
|
||||
if len(filtered) == 0 {
|
||||
t.Fatal("Filter too restrictive, no images left?")
|
||||
}
|
||||
|
||||
image := filtered[0]
|
||||
for _, im := range filtered {
|
||||
if im.PublishedDate > image.PublishedDate {
|
||||
image = im
|
||||
}
|
||||
}
|
||||
|
||||
t.Logf("Selecting image '%s'", image.Name)
|
||||
return image
|
||||
}
|
||||
|
||||
func GenerateName() string {
|
||||
from := "1234567890abcdefghijklmnopqrstuvwxyz"
|
||||
return "sdk" + GenerateString(12, from)
|
||||
}
|
||||
|
||||
func GeneratePassword() string {
|
||||
pw := GenerateString(20, "1234567890") +
|
||||
GenerateString(20, "abcdefghijklmnopqrstuvwxyz") +
|
||||
GenerateString(20, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
|
||||
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
i := rnd.Intn(len(pw)-2) + 1
|
||||
|
||||
pw = string(append([]uint8(pw[i:]), pw[:i-1]...))
|
||||
|
||||
return pw
|
||||
}
|
||||
|
||||
func GenerateString(length int, from string) string {
|
||||
str := ""
|
||||
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
for len(str) < length {
|
||||
str += string(from[rnd.Intn(len(from))])
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
type asyncFunc func() (operationId management.OperationID, err error)
|
||||
|
||||
func Await(client management.Client, async asyncFunc) error {
|
||||
requestID, err := async()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return client.WaitForOperation(requestID, nil)
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package vmutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
vm "github.com/Azure/azure-sdk-for-go/management/virtualmachine"
|
||||
)
|
||||
|
||||
// ConfigureWithPublicSSH adds configuration exposing port 22 externally
|
||||
func ConfigureWithPublicSSH(role *vm.Role) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
return ConfigureWithExternalPort(role, "SSH", 22, 22, vm.InputEndpointProtocolTCP)
|
||||
}
|
||||
|
||||
// ConfigureWithPublicRDP adds configuration exposing port 3389 externally
|
||||
func ConfigureWithPublicRDP(role *vm.Role) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
return ConfigureWithExternalPort(role, "RDP", 3389, 3389, vm.InputEndpointProtocolTCP)
|
||||
}
|
||||
|
||||
// ConfigureWithPublicPowerShell adds configuration exposing port 5986
|
||||
// externally
|
||||
func ConfigureWithPublicPowerShell(role *vm.Role) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
return ConfigureWithExternalPort(role, "PowerShell", 5986, 5986, vm.InputEndpointProtocolTCP)
|
||||
}
|
||||
|
||||
// ConfigureWithExternalPort adds a new InputEndpoint to the Role, exposing a
|
||||
// port externally
|
||||
func ConfigureWithExternalPort(role *vm.Role, name string, localport, externalport int, protocol vm.InputEndpointProtocol) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
role.ConfigurationSets = updateOrAddConfig(role.ConfigurationSets, vm.ConfigurationSetTypeNetwork,
|
||||
func(config *vm.ConfigurationSet) {
|
||||
config.InputEndpoints = append(config.InputEndpoints, vm.InputEndpoint{
|
||||
LocalPort: localport,
|
||||
Name: name,
|
||||
Port: externalport,
|
||||
Protocol: protocol,
|
||||
})
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConfigureWithSecurityGroup associates the Role with a specific network security group
|
||||
func ConfigureWithSecurityGroup(role *vm.Role, networkSecurityGroup string) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
role.ConfigurationSets = updateOrAddConfig(role.ConfigurationSets, vm.ConfigurationSetTypeNetwork,
|
||||
func(config *vm.ConfigurationSet) {
|
||||
config.NetworkSecurityGroup = networkSecurityGroup
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConfigureWithSubnet associates the Role with a specific subnet
|
||||
func ConfigureWithSubnet(role *vm.Role, subnet string) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
role.ConfigurationSets = updateOrAddConfig(role.ConfigurationSets, vm.ConfigurationSetTypeNetwork,
|
||||
func(config *vm.ConfigurationSet) {
|
||||
config.SubnetNames = append(config.SubnetNames, subnet)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
package vmutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
lc "github.com/Azure/azure-sdk-for-go/management/location"
|
||||
vm "github.com/Azure/azure-sdk-for-go/management/virtualmachine"
|
||||
)
|
||||
|
||||
// IsRoleSizeValid retrieves the available rolesizes using
|
||||
// vmclient.GetRoleSizeList() and returns whether that the provided roleSizeName
|
||||
// is part of that list
|
||||
func IsRoleSizeValid(vmclient vm.VirtualMachineClient, roleSizeName string) (bool, error) {
|
||||
if roleSizeName == "" {
|
||||
return false, fmt.Errorf(errParamNotSpecified, "roleSizeName")
|
||||
}
|
||||
|
||||
roleSizeList, err := vmclient.GetRoleSizeList()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, roleSize := range roleSizeList.RoleSizes {
|
||||
if roleSize.Name == roleSizeName {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// IsRoleSizeAvailableInLocation retrieves all available sizes in the specified
|
||||
// location and returns whether that the provided roleSizeName is part of that list.
|
||||
func IsRoleSizeAvailableInLocation(managementclient management.Client, location, roleSizeName string) (bool, error) {
|
||||
if location == "" {
|
||||
return false, fmt.Errorf(errParamNotSpecified, "location")
|
||||
}
|
||||
if roleSizeName == "" {
|
||||
return false, fmt.Errorf(errParamNotSpecified, "roleSizeName")
|
||||
}
|
||||
|
||||
locationClient := lc.NewClient(managementclient)
|
||||
locationInfo, err := getLocation(locationClient, location)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, availableRoleSize := range locationInfo.VirtualMachineRoleSizes {
|
||||
if availableRoleSize == roleSizeName {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func getLocation(c lc.LocationClient, location string) (*lc.Location, error) {
|
||||
if location == "" {
|
||||
return nil, fmt.Errorf(errParamNotSpecified, "location")
|
||||
}
|
||||
|
||||
locations, err := c.ListLocations()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, existingLocation := range locations.Locations {
|
||||
if existingLocation.Name != location {
|
||||
continue
|
||||
}
|
||||
|
||||
return &existingLocation, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Invalid location: %s. Available locations: %s", location, locations)
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package vmutils
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
vm "github.com/Azure/azure-sdk-for-go/management/virtualmachine"
|
||||
)
|
||||
|
||||
// WaitForDeploymentPowerState blocks until all role instances in deployment
|
||||
// reach desired power state.
|
||||
func WaitForDeploymentPowerState(client management.Client, cloudServiceName, deploymentName string, desiredPowerstate vm.PowerState) error {
|
||||
for {
|
||||
deployment, err := vm.NewClient(client).GetDeployment(cloudServiceName, deploymentName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if allInstancesInPowerState(deployment.RoleInstanceList, desiredPowerstate) {
|
||||
return nil
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func allInstancesInPowerState(instances []vm.RoleInstance, desiredPowerstate vm.PowerState) bool {
|
||||
for _, r := range instances {
|
||||
if r.PowerState != desiredPowerstate {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// WaitForDeploymentInstanceStatus blocks until all role instances in deployment
|
||||
// reach desired InstanceStatus.
|
||||
func WaitForDeploymentInstanceStatus(client management.Client, cloudServiceName, deploymentName string, desiredInstanceStatus vm.InstanceStatus) error {
|
||||
for {
|
||||
deployment, err := vm.NewClient(client).GetDeployment(cloudServiceName, deploymentName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if allInstancesInInstanceStatus(deployment.RoleInstanceList, desiredInstanceStatus) {
|
||||
return nil
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func allInstancesInInstanceStatus(instances []vm.RoleInstance, desiredInstancestatus vm.InstanceStatus) bool {
|
||||
for _, r := range instances {
|
||||
if r.InstanceStatus != desiredInstancestatus {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
// Package vmutils provides convenience methods for creating Virtual
|
||||
// Machine Role configurations.
|
||||
package vmutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
vm "github.com/Azure/azure-sdk-for-go/management/virtualmachine"
|
||||
)
|
||||
|
||||
const (
|
||||
errParamNotSpecified = "Parameter %s is not specified."
|
||||
)
|
||||
|
||||
// NewVMConfiguration creates configuration for a new virtual machine Role.
|
||||
func NewVMConfiguration(name string, roleSize string) vm.Role {
|
||||
return vm.Role{
|
||||
RoleName: name,
|
||||
RoleType: "PersistentVMRole",
|
||||
RoleSize: roleSize,
|
||||
ProvisionGuestAgent: true,
|
||||
}
|
||||
}
|
||||
|
||||
// ConfigureForLinux adds configuration when deploying a generalized Linux
|
||||
// image. If "password" is left empty, SSH password security will be disabled by
|
||||
// default. Certificates with SSH public keys should already be uploaded to the
|
||||
// cloud service where the VM will be deployed and referenced here only by their
|
||||
// thumbprint.
|
||||
func ConfigureForLinux(role *vm.Role, hostname, user, password string, sshPubkeyCertificateThumbprint ...string) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
role.ConfigurationSets = updateOrAddConfig(role.ConfigurationSets, vm.ConfigurationSetTypeLinuxProvisioning,
|
||||
func(config *vm.ConfigurationSet) {
|
||||
config.HostName = hostname
|
||||
config.UserName = user
|
||||
config.UserPassword = password
|
||||
if password != "" {
|
||||
config.DisableSSHPasswordAuthentication = "false"
|
||||
}
|
||||
if len(sshPubkeyCertificateThumbprint) != 0 {
|
||||
config.SSH = &vm.SSH{}
|
||||
for _, k := range sshPubkeyCertificateThumbprint {
|
||||
config.SSH.PublicKeys = append(config.SSH.PublicKeys,
|
||||
vm.PublicKey{
|
||||
Fingerprint: k,
|
||||
Path: "/home/" + user + "/.ssh/authorized_keys",
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConfigureForWindows adds configuration when deploying a generalized
|
||||
// Windows image. timeZone can be left empty. For a complete list of supported
|
||||
// time zone entries, you can either refer to the values listed in the registry
|
||||
// entry "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time
|
||||
// Zones" or you can use the tzutil command-line tool to list the valid time.
|
||||
func ConfigureForWindows(role *vm.Role, hostname, user, password string, enableAutomaticUpdates bool, timeZone string) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
role.ConfigurationSets = updateOrAddConfig(role.ConfigurationSets, vm.ConfigurationSetTypeWindowsProvisioning,
|
||||
func(config *vm.ConfigurationSet) {
|
||||
config.ComputerName = hostname
|
||||
config.AdminUsername = user
|
||||
config.AdminPassword = password
|
||||
config.EnableAutomaticUpdates = enableAutomaticUpdates
|
||||
config.TimeZone = timeZone
|
||||
},
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConfigureWithCustomDataForLinux configures custom data for Linux-based images.
|
||||
// The customData contains either cloud-init or shell script to be executed upon start.
|
||||
//
|
||||
// The function expects the customData to be base64-encoded.
|
||||
func ConfigureWithCustomDataForLinux(role *vm.Role, customData string) error {
|
||||
return configureWithCustomData(role, customData, vm.ConfigurationSetTypeLinuxProvisioning)
|
||||
}
|
||||
|
||||
// ConfigureWithCustomDataForWindows configures custom data for Windows-based images.
|
||||
// The customData contains either cloud-init or shell script to be executed upon start.
|
||||
//
|
||||
// The function expects the customData to be base64-encoded.
|
||||
func ConfigureWithCustomDataForWindows(role *vm.Role, customData string) error {
|
||||
return configureWithCustomData(role, customData, vm.ConfigurationSetTypeWindowsProvisioning)
|
||||
}
|
||||
|
||||
func configureWithCustomData(role *vm.Role, customData string, typ vm.ConfigurationSetType) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
role.ConfigurationSets = updateOrAddConfig(role.ConfigurationSets, typ,
|
||||
func(config *vm.ConfigurationSet) {
|
||||
config.CustomData = customData
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConfigureWindowsToJoinDomain adds configuration to join a new Windows vm to a
|
||||
// domain. "username" must be in UPN form (user@domain.com), "machineOU" can be
|
||||
// left empty
|
||||
func ConfigureWindowsToJoinDomain(role *vm.Role, username, password, domainToJoin, machineOU string) error {
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
winconfig := findConfig(role.ConfigurationSets, vm.ConfigurationSetTypeWindowsProvisioning)
|
||||
if winconfig != nil {
|
||||
winconfig.DomainJoin = &vm.DomainJoin{
|
||||
Credentials: vm.Credentials{Username: username, Password: password},
|
||||
JoinDomain: domainToJoin,
|
||||
MachineObjectOU: machineOU,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ConfigureWinRMListener(role *vm.Role, protocol vm.WinRMProtocol, certificateThumbprint string) error {
|
||||
|
||||
if role == nil {
|
||||
return fmt.Errorf(errParamNotSpecified, "role")
|
||||
}
|
||||
|
||||
winconfig := findConfig(role.ConfigurationSets, vm.ConfigurationSetTypeWindowsProvisioning)
|
||||
|
||||
if winconfig != nil {
|
||||
|
||||
listener := vm.WinRMListener{
|
||||
Protocol: protocol,
|
||||
CertificateThumbprint: certificateThumbprint,
|
||||
}
|
||||
|
||||
if winconfig.WinRMListeners == nil {
|
||||
winconfig.WinRMListeners = &[]vm.WinRMListener{}
|
||||
}
|
||||
|
||||
currentListeners := *winconfig.WinRMListeners
|
||||
|
||||
// replace existing listener if it's already configured
|
||||
for i, existingListener := range currentListeners {
|
||||
if existingListener.Protocol == protocol {
|
||||
currentListeners[i] = listener
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise append to list of listeners
|
||||
newListeners := append(currentListeners, listener)
|
||||
winconfig.WinRMListeners = &newListeners
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("WindowsProvisioningConfigurationSet not found in 'role'")
|
||||
}
|
||||
|
||||
func ConfigureWinRMOverHTTP(role *vm.Role) error {
|
||||
return ConfigureWinRMListener(role, vm.WinRMProtocolHTTP, "")
|
||||
}
|
||||
|
||||
func ConfigureWinRMOverHTTPS(role *vm.Role, certificateThumbprint string) error {
|
||||
return ConfigureWinRMListener(role, vm.WinRMProtocolHTTPS, certificateThumbprint)
|
||||
}
|
||||
+440
@@ -0,0 +1,440 @@
|
||||
package vmutils
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"testing"
|
||||
|
||||
vmdisk "github.com/Azure/azure-sdk-for-go/management/virtualmachinedisk"
|
||||
)
|
||||
|
||||
func TestNewLinuxVmRemoteImage(t *testing.T) {
|
||||
role := NewVMConfiguration("myvm", "Standard_D3")
|
||||
ConfigureDeploymentFromRemoteImage(&role,
|
||||
"http://remote.host/some.vhd?sv=12&sig=ukhfiuwef78687", "Linux",
|
||||
"myvm-os-disk", "http://mystorageacct.blob.core.windows.net/vhds/mybrandnewvm.vhd",
|
||||
"OSDisk")
|
||||
ConfigureForLinux(&role, "myvm", "azureuser", "P@ssword", "2398yyKJGd78e2389ydfncuirowebhf89yh3IUOBY")
|
||||
ConfigureWithPublicSSH(&role)
|
||||
|
||||
bytes, err := xml.MarshalIndent(role, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := `<Role>
|
||||
<RoleName>myvm</RoleName>
|
||||
<RoleType>PersistentVMRole</RoleType>
|
||||
<ConfigurationSets>
|
||||
<ConfigurationSet>
|
||||
<ConfigurationSetType>LinuxProvisioningConfiguration</ConfigurationSetType>
|
||||
<StoredCertificateSettings></StoredCertificateSettings>
|
||||
<HostName>myvm</HostName>
|
||||
<UserName>azureuser</UserName>
|
||||
<UserPassword>P@ssword</UserPassword>
|
||||
<DisableSshPasswordAuthentication>false</DisableSshPasswordAuthentication>
|
||||
<SSH>
|
||||
<PublicKeys>
|
||||
<PublicKey>
|
||||
<Fingerprint>2398yyKJGd78e2389ydfncuirowebhf89yh3IUOBY</Fingerprint>
|
||||
<Path>/home/azureuser/.ssh/authorized_keys</Path>
|
||||
</PublicKey>
|
||||
</PublicKeys>
|
||||
<KeyPairs></KeyPairs>
|
||||
</SSH>
|
||||
<InputEndpoints></InputEndpoints>
|
||||
<SubnetNames></SubnetNames>
|
||||
<PublicIPs></PublicIPs>
|
||||
</ConfigurationSet>
|
||||
<ConfigurationSet>
|
||||
<ConfigurationSetType>NetworkConfiguration</ConfigurationSetType>
|
||||
<StoredCertificateSettings></StoredCertificateSettings>
|
||||
<InputEndpoints>
|
||||
<InputEndpoint>
|
||||
<LocalPort>22</LocalPort>
|
||||
<Name>SSH</Name>
|
||||
<Port>22</Port>
|
||||
<Protocol>TCP</Protocol>
|
||||
</InputEndpoint>
|
||||
</InputEndpoints>
|
||||
<SubnetNames></SubnetNames>
|
||||
<PublicIPs></PublicIPs>
|
||||
</ConfigurationSet>
|
||||
</ConfigurationSets>
|
||||
<DataVirtualHardDisks></DataVirtualHardDisks>
|
||||
<OSVirtualHardDisk>
|
||||
<DiskLabel>OSDisk</DiskLabel>
|
||||
<DiskName>myvm-os-disk</DiskName>
|
||||
<MediaLink>http://mystorageacct.blob.core.windows.net/vhds/mybrandnewvm.vhd</MediaLink>
|
||||
<OS>Linux</OS>
|
||||
<RemoteSourceImageLink>http://remote.host/some.vhd?sv=12&sig=ukhfiuwef78687</RemoteSourceImageLink>
|
||||
</OSVirtualHardDisk>
|
||||
<RoleSize>Standard_D3</RoleSize>
|
||||
<ProvisionGuestAgent>true</ProvisionGuestAgent>
|
||||
</Role>`
|
||||
|
||||
if string(bytes) != expected {
|
||||
t.Fatalf("Expected marshalled xml to be %q, but got %q", expected, string(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewLinuxVmPlatformImage(t *testing.T) {
|
||||
role := NewVMConfiguration("myplatformvm", "Standard_D3")
|
||||
ConfigureDeploymentFromPlatformImage(&role,
|
||||
"b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-14_04_2_LTS-amd64-server-20150309-en-us-30GB",
|
||||
"http://mystorageacct.blob.core.windows.net/vhds/mybrandnewvm.vhd", "mydisklabel")
|
||||
ConfigureForLinux(&role, "myvm", "azureuser", "", "2398yyKJGd78e2389ydfncuirdebhf89yh3IUOBY")
|
||||
|
||||
bytes, err := xml.MarshalIndent(role, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := `<Role>
|
||||
<RoleName>myplatformvm</RoleName>
|
||||
<RoleType>PersistentVMRole</RoleType>
|
||||
<ConfigurationSets>
|
||||
<ConfigurationSet>
|
||||
<ConfigurationSetType>LinuxProvisioningConfiguration</ConfigurationSetType>
|
||||
<StoredCertificateSettings></StoredCertificateSettings>
|
||||
<HostName>myvm</HostName>
|
||||
<UserName>azureuser</UserName>
|
||||
<SSH>
|
||||
<PublicKeys>
|
||||
<PublicKey>
|
||||
<Fingerprint>2398yyKJGd78e2389ydfncuirdebhf89yh3IUOBY</Fingerprint>
|
||||
<Path>/home/azureuser/.ssh/authorized_keys</Path>
|
||||
</PublicKey>
|
||||
</PublicKeys>
|
||||
<KeyPairs></KeyPairs>
|
||||
</SSH>
|
||||
<InputEndpoints></InputEndpoints>
|
||||
<SubnetNames></SubnetNames>
|
||||
<PublicIPs></PublicIPs>
|
||||
</ConfigurationSet>
|
||||
</ConfigurationSets>
|
||||
<DataVirtualHardDisks></DataVirtualHardDisks>
|
||||
<OSVirtualHardDisk>
|
||||
<MediaLink>http://mystorageacct.blob.core.windows.net/vhds/mybrandnewvm.vhd</MediaLink>
|
||||
<SourceImageName>b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-14_04_2_LTS-amd64-server-20150309-en-us-30GB</SourceImageName>
|
||||
</OSVirtualHardDisk>
|
||||
<RoleSize>Standard_D3</RoleSize>
|
||||
<ProvisionGuestAgent>true</ProvisionGuestAgent>
|
||||
</Role>`
|
||||
|
||||
if string(bytes) != expected {
|
||||
t.Fatalf("Expected marshalled xml to be %q, but got %q", expected, string(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewVmFromVMImage(t *testing.T) {
|
||||
role := NewVMConfiguration("restoredbackup", "Standard_D1")
|
||||
ConfigureDeploymentFromPublishedVMImage(&role, "myvm-backup-20150209",
|
||||
"http://mystorageacct.blob.core.windows.net/vhds/myoldnewvm.vhd", false)
|
||||
|
||||
bytes, err := xml.MarshalIndent(role, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := `<Role>
|
||||
<RoleName>restoredbackup</RoleName>
|
||||
<RoleType>PersistentVMRole</RoleType>
|
||||
<ConfigurationSets></ConfigurationSets>
|
||||
<VMImageName>myvm-backup-20150209</VMImageName>
|
||||
<MediaLocation>http://mystorageacct.blob.core.windows.net/vhds/myoldnewvm.vhd</MediaLocation>
|
||||
<DataVirtualHardDisks></DataVirtualHardDisks>
|
||||
<RoleSize>Standard_D1</RoleSize>
|
||||
</Role>`
|
||||
|
||||
if string(bytes) != expected {
|
||||
t.Fatalf("Expected marshalled xml to be %q, but got %q", expected, string(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewVmFromExistingDisk(t *testing.T) {
|
||||
role := NewVMConfiguration("blobvm", "Standard_D14")
|
||||
ConfigureDeploymentFromExistingOSDisk(&role, "myvm-backup-20150209", "OSDisk")
|
||||
ConfigureForWindows(&role, "WINVM", "azuser", "P2ssw@rd", true, "")
|
||||
ConfigureWindowsToJoinDomain(&role, "user@domain.com", "youReN3verG0nnaGu3ss", "redmond.corp.contoso.com", "")
|
||||
ConfigureWithNewDataDisk(&role, "my-brand-new-disk", "http://account.blob.core.windows.net/vhds/newdatadisk.vhd",
|
||||
30, vmdisk.HostCachingTypeReadWrite)
|
||||
ConfigureWithExistingDataDisk(&role, "data-disk", vmdisk.HostCachingTypeReadOnly)
|
||||
|
||||
bytes, err := xml.MarshalIndent(role, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := `<Role>
|
||||
<RoleName>blobvm</RoleName>
|
||||
<RoleType>PersistentVMRole</RoleType>
|
||||
<ConfigurationSets>
|
||||
<ConfigurationSet>
|
||||
<ConfigurationSetType>WindowsProvisioningConfiguration</ConfigurationSetType>
|
||||
<ComputerName>WINVM</ComputerName>
|
||||
<AdminPassword>P2ssw@rd</AdminPassword>
|
||||
<EnableAutomaticUpdates>true</EnableAutomaticUpdates>
|
||||
<DomainJoin>
|
||||
<Credentials>
|
||||
<Domain></Domain>
|
||||
<Username>user@domain.com</Username>
|
||||
<Password>youReN3verG0nnaGu3ss</Password>
|
||||
</Credentials>
|
||||
<JoinDomain>redmond.corp.contoso.com</JoinDomain>
|
||||
</DomainJoin>
|
||||
<StoredCertificateSettings></StoredCertificateSettings>
|
||||
<AdminUsername>azuser</AdminUsername>
|
||||
<InputEndpoints></InputEndpoints>
|
||||
<SubnetNames></SubnetNames>
|
||||
<PublicIPs></PublicIPs>
|
||||
</ConfigurationSet>
|
||||
</ConfigurationSets>
|
||||
<DataVirtualHardDisks>
|
||||
<DataVirtualHardDisk>
|
||||
<HostCaching>ReadWrite</HostCaching>
|
||||
<DiskLabel>my-brand-new-disk</DiskLabel>
|
||||
<LogicalDiskSizeInGB>30</LogicalDiskSizeInGB>
|
||||
<MediaLink>http://account.blob.core.windows.net/vhds/newdatadisk.vhd</MediaLink>
|
||||
</DataVirtualHardDisk>
|
||||
<DataVirtualHardDisk>
|
||||
<HostCaching>ReadOnly</HostCaching>
|
||||
<DiskName>data-disk</DiskName>
|
||||
<Lun>1</Lun>
|
||||
</DataVirtualHardDisk>
|
||||
</DataVirtualHardDisks>
|
||||
<OSVirtualHardDisk>
|
||||
<DiskLabel>OSDisk</DiskLabel>
|
||||
<DiskName>myvm-backup-20150209</DiskName>
|
||||
</OSVirtualHardDisk>
|
||||
<RoleSize>Standard_D14</RoleSize>
|
||||
<ProvisionGuestAgent>true</ProvisionGuestAgent>
|
||||
</Role>`
|
||||
|
||||
if string(bytes) != expected {
|
||||
t.Fatalf("Expected marshalled xml to be %q, but got %q", expected, string(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
func TestWinRMOverHttps(t *testing.T) {
|
||||
role := NewVMConfiguration("winrmoverhttp", "Standard_D1")
|
||||
ConfigureForWindows(&role, "WINVM", "azuser", "P2ssw@rd", true, "")
|
||||
ConfigureWinRMOverHTTPS(&role, "abcdef")
|
||||
|
||||
bytes, err := xml.MarshalIndent(role, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := `<Role>
|
||||
<RoleName>winrmoverhttp</RoleName>
|
||||
<RoleType>PersistentVMRole</RoleType>
|
||||
<ConfigurationSets>
|
||||
<ConfigurationSet>
|
||||
<ConfigurationSetType>WindowsProvisioningConfiguration</ConfigurationSetType>
|
||||
<ComputerName>WINVM</ComputerName>
|
||||
<AdminPassword>P2ssw@rd</AdminPassword>
|
||||
<EnableAutomaticUpdates>true</EnableAutomaticUpdates>
|
||||
<StoredCertificateSettings></StoredCertificateSettings>
|
||||
<WinRM>
|
||||
<Listeners>
|
||||
<Listener>
|
||||
<Protocol>Https</Protocol>
|
||||
<CertificateThumbprint>abcdef</CertificateThumbprint>
|
||||
</Listener>
|
||||
</Listeners>
|
||||
</WinRM>
|
||||
<AdminUsername>azuser</AdminUsername>
|
||||
<InputEndpoints></InputEndpoints>
|
||||
<SubnetNames></SubnetNames>
|
||||
<PublicIPs></PublicIPs>
|
||||
</ConfigurationSet>
|
||||
</ConfigurationSets>
|
||||
<DataVirtualHardDisks></DataVirtualHardDisks>
|
||||
<RoleSize>Standard_D1</RoleSize>
|
||||
<ProvisionGuestAgent>true</ProvisionGuestAgent>
|
||||
</Role>`
|
||||
|
||||
if string(bytes) != expected {
|
||||
t.Fatalf("Expected marshalled xml to be %q, but got %q", expected, string(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
func TestWinRMOverHttpsWithNoThumbprint(t *testing.T) {
|
||||
role := NewVMConfiguration("winrmoverhttp", "Standard_D1")
|
||||
ConfigureForWindows(&role, "WINVM", "azuser", "P2ssw@rd", true, "")
|
||||
ConfigureWinRMOverHTTPS(&role, "")
|
||||
|
||||
bytes, err := xml.MarshalIndent(role, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := `<Role>
|
||||
<RoleName>winrmoverhttp</RoleName>
|
||||
<RoleType>PersistentVMRole</RoleType>
|
||||
<ConfigurationSets>
|
||||
<ConfigurationSet>
|
||||
<ConfigurationSetType>WindowsProvisioningConfiguration</ConfigurationSetType>
|
||||
<ComputerName>WINVM</ComputerName>
|
||||
<AdminPassword>P2ssw@rd</AdminPassword>
|
||||
<EnableAutomaticUpdates>true</EnableAutomaticUpdates>
|
||||
<StoredCertificateSettings></StoredCertificateSettings>
|
||||
<WinRM>
|
||||
<Listeners>
|
||||
<Listener>
|
||||
<Protocol>Https</Protocol>
|
||||
</Listener>
|
||||
</Listeners>
|
||||
</WinRM>
|
||||
<AdminUsername>azuser</AdminUsername>
|
||||
<InputEndpoints></InputEndpoints>
|
||||
<SubnetNames></SubnetNames>
|
||||
<PublicIPs></PublicIPs>
|
||||
</ConfigurationSet>
|
||||
</ConfigurationSets>
|
||||
<DataVirtualHardDisks></DataVirtualHardDisks>
|
||||
<RoleSize>Standard_D1</RoleSize>
|
||||
<ProvisionGuestAgent>true</ProvisionGuestAgent>
|
||||
</Role>`
|
||||
|
||||
if string(bytes) != expected {
|
||||
t.Fatalf("Expected marshalled xml to be %q, but got %q", expected, string(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
func TestWinRMOverHttp(t *testing.T) {
|
||||
role := NewVMConfiguration("winrmoverhttp", "Standard_D1")
|
||||
ConfigureForWindows(&role, "WINVM", "azuser", "P2ssw@rd", true, "")
|
||||
ConfigureWinRMOverHTTP(&role)
|
||||
|
||||
bytes, err := xml.MarshalIndent(role, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := `<Role>
|
||||
<RoleName>winrmoverhttp</RoleName>
|
||||
<RoleType>PersistentVMRole</RoleType>
|
||||
<ConfigurationSets>
|
||||
<ConfigurationSet>
|
||||
<ConfigurationSetType>WindowsProvisioningConfiguration</ConfigurationSetType>
|
||||
<ComputerName>WINVM</ComputerName>
|
||||
<AdminPassword>P2ssw@rd</AdminPassword>
|
||||
<EnableAutomaticUpdates>true</EnableAutomaticUpdates>
|
||||
<StoredCertificateSettings></StoredCertificateSettings>
|
||||
<WinRM>
|
||||
<Listeners>
|
||||
<Listener>
|
||||
<Protocol>Http</Protocol>
|
||||
</Listener>
|
||||
</Listeners>
|
||||
</WinRM>
|
||||
<AdminUsername>azuser</AdminUsername>
|
||||
<InputEndpoints></InputEndpoints>
|
||||
<SubnetNames></SubnetNames>
|
||||
<PublicIPs></PublicIPs>
|
||||
</ConfigurationSet>
|
||||
</ConfigurationSets>
|
||||
<DataVirtualHardDisks></DataVirtualHardDisks>
|
||||
<RoleSize>Standard_D1</RoleSize>
|
||||
<ProvisionGuestAgent>true</ProvisionGuestAgent>
|
||||
</Role>`
|
||||
|
||||
if string(bytes) != expected {
|
||||
t.Fatalf("Expected marshalled xml to be %q, but got %q", expected, string(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSettingWinRMOverHttpTwice(t *testing.T) {
|
||||
role := NewVMConfiguration("winrmoverhttp", "Standard_D1")
|
||||
ConfigureForWindows(&role, "WINVM", "azuser", "P2ssw@rd", true, "")
|
||||
ConfigureWinRMOverHTTP(&role)
|
||||
ConfigureWinRMOverHTTP(&role)
|
||||
|
||||
bytes, err := xml.MarshalIndent(role, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := `<Role>
|
||||
<RoleName>winrmoverhttp</RoleName>
|
||||
<RoleType>PersistentVMRole</RoleType>
|
||||
<ConfigurationSets>
|
||||
<ConfigurationSet>
|
||||
<ConfigurationSetType>WindowsProvisioningConfiguration</ConfigurationSetType>
|
||||
<ComputerName>WINVM</ComputerName>
|
||||
<AdminPassword>P2ssw@rd</AdminPassword>
|
||||
<EnableAutomaticUpdates>true</EnableAutomaticUpdates>
|
||||
<StoredCertificateSettings></StoredCertificateSettings>
|
||||
<WinRM>
|
||||
<Listeners>
|
||||
<Listener>
|
||||
<Protocol>Http</Protocol>
|
||||
</Listener>
|
||||
</Listeners>
|
||||
</WinRM>
|
||||
<AdminUsername>azuser</AdminUsername>
|
||||
<InputEndpoints></InputEndpoints>
|
||||
<SubnetNames></SubnetNames>
|
||||
<PublicIPs></PublicIPs>
|
||||
</ConfigurationSet>
|
||||
</ConfigurationSets>
|
||||
<DataVirtualHardDisks></DataVirtualHardDisks>
|
||||
<RoleSize>Standard_D1</RoleSize>
|
||||
<ProvisionGuestAgent>true</ProvisionGuestAgent>
|
||||
</Role>`
|
||||
|
||||
if string(bytes) != expected {
|
||||
t.Fatalf("Expected marshalled xml to be %q, but got %q", expected, string(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSettingWinRMOverHttpAndHttpsTwice(t *testing.T) {
|
||||
role := NewVMConfiguration("winrmoverhttp", "Standard_D1")
|
||||
ConfigureForWindows(&role, "WINVM", "azuser", "P2ssw@rd", true, "")
|
||||
ConfigureWinRMOverHTTP(&role)
|
||||
ConfigureWinRMOverHTTPS(&role, "")
|
||||
ConfigureWinRMOverHTTP(&role)
|
||||
ConfigureWinRMOverHTTPS(&role, "abcdef")
|
||||
|
||||
bytes, err := xml.MarshalIndent(role, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := `<Role>
|
||||
<RoleName>winrmoverhttp</RoleName>
|
||||
<RoleType>PersistentVMRole</RoleType>
|
||||
<ConfigurationSets>
|
||||
<ConfigurationSet>
|
||||
<ConfigurationSetType>WindowsProvisioningConfiguration</ConfigurationSetType>
|
||||
<ComputerName>WINVM</ComputerName>
|
||||
<AdminPassword>P2ssw@rd</AdminPassword>
|
||||
<EnableAutomaticUpdates>true</EnableAutomaticUpdates>
|
||||
<StoredCertificateSettings></StoredCertificateSettings>
|
||||
<WinRM>
|
||||
<Listeners>
|
||||
<Listener>
|
||||
<Protocol>Http</Protocol>
|
||||
</Listener>
|
||||
<Listener>
|
||||
<Protocol>Https</Protocol>
|
||||
<CertificateThumbprint>abcdef</CertificateThumbprint>
|
||||
</Listener>
|
||||
</Listeners>
|
||||
</WinRM>
|
||||
<AdminUsername>azuser</AdminUsername>
|
||||
<InputEndpoints></InputEndpoints>
|
||||
<SubnetNames></SubnetNames>
|
||||
<PublicIPs></PublicIPs>
|
||||
</ConfigurationSet>
|
||||
</ConfigurationSets>
|
||||
<DataVirtualHardDisks></DataVirtualHardDisks>
|
||||
<RoleSize>Standard_D1</RoleSize>
|
||||
<ProvisionGuestAgent>true</ProvisionGuestAgent>
|
||||
</Role>`
|
||||
|
||||
if string(bytes) != expected {
|
||||
t.Fatalf("Expected marshalled xml to be %q, but got %q", expected, string(bytes))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user