diff --git a/clients/vnetClient/entities.go b/clients/vnetClient/entities.go new file mode 100644 index 000000000000..cfa5a94d958e --- /dev/null +++ b/clients/vnetClient/entities.go @@ -0,0 +1,81 @@ +package vnetClient + +import ( + "encoding/xml" +) + +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" + +//NetworkConfiguration represents the network configuration for an entire Azure +//subscription. TODO: Nicer builder methods for these that abstract away the +//underlying structure +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"` +} + +//NewNetworkConfiguration creates a new empty NetworkConfiguration structure for +//further configuration. The XML namespaces are set correctly. +func 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 (self *NetworkConfiguration) setXmlNamespaces() { + self.XmlNamespaceXsd = xmlNamespaceXsd + self.XmlNamespaceXsi = xmlNamespaceXsi + self.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,omitempty>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,omitempty>DnsServerRef"` +} + +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 +} diff --git a/clients/vnetClient/vnetClient.go b/clients/vnetClient/vnetClient.go new file mode 100644 index 000000000000..f9638e1d3f6e --- /dev/null +++ b/clients/vnetClient/vnetClient.go @@ -0,0 +1,49 @@ +package vnetClient + +import ( + "encoding/xml" + azure "github.com/MSOpenTech/azure-sdk-for-go" +) + +const ( + azureNetworkConfigurationURL = "services/networking/media" +) + +//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 GetVirtualNetworkConfiguration() (NetworkConfiguration, error) { + networkConfiguration := NewNetworkConfiguration() + response, err := azure.SendAzureGetRequest(azureNetworkConfigurationURL) + if err != nil { + return networkConfiguration, err + } + + err = xml.Unmarshal(response, &networkConfiguration) + if err != nil { + return networkConfiguration, err + } + + return networkConfiguration, nil +} + +//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 SetVirtualNetworkConfiguration(networkConfiguration NetworkConfiguration) error { + networkConfiguration.setXmlNamespaces() + networkConfigurationBytes, err := xml.Marshal(networkConfiguration) + if err != nil { + return err + } + + requestId, err := azure.SendAzurePutRequest(azureNetworkConfigurationURL, "text/plain", networkConfigurationBytes) + if err != nil { + return err + } + + err = azure.WaitAsyncOperation(requestId) + return err +} diff --git a/common.go b/common.go index 6808f016a42f..248f035fd3c8 100644 --- a/common.go +++ b/common.go @@ -17,12 +17,12 @@ import ( const ( paramNotSpecifiedError = "Parameter %s is not specified." - azureManagementDnsName = "https://management.core.windows.net" - msVersionHeader = "x-ms-version" - msVersionHeaderValue = "2014-05-01" - contentHeader = "Content-Type" - contentHeaderValue = "application/xml" - requestIdHeader = "X-Ms-Request-Id" + azureManagementDnsName = "https://management.core.windows.net" + msVersionHeader = "x-ms-version" + msVersionHeaderValue = "2014-05-01" + contentHeader = "Content-Type" + defaultContentHeaderValue = "application/xml" + requestIdHeader = "X-Ms-Request-Id" ) //Region public methods starts @@ -32,7 +32,7 @@ func SendAzureGetRequest(url string) ([]byte, error) { return nil, fmt.Errorf(paramNotSpecifiedError, "url") } - response, err := SendAzureRequest(url, "GET", nil) + response, err := SendAzureRequest(url, "GET", "", nil) if err != nil { return nil, err } @@ -46,7 +46,21 @@ func SendAzurePostRequest(url string, data []byte) (string, error) { return "", fmt.Errorf(paramNotSpecifiedError, "url") } - response, err := SendAzureRequest(url, "POST", data) + response, err := SendAzureRequest(url, "POST", "", data) + if err != nil { + return "", err + } + + requestId := response.Header[requestIdHeader] + return requestId[0], nil +} + +func SendAzurePutRequest(url string, contentType string, data []byte) (string, error) { + if len(url) == 0 { + return "", fmt.Errorf(paramNotSpecifiedError, contentType, "url") + } + + response, err := SendAzureRequest(url, "PUT", contentType, data) if err != nil { return "", err } @@ -60,7 +74,7 @@ func SendAzureDeleteRequest(url string) (string, error) { return "", fmt.Errorf(paramNotSpecifiedError, "url") } - response, err := SendAzureRequest(url, "DELETE", nil) + response, err := SendAzureRequest(url, "DELETE", "", nil) if err != nil { return "", err } @@ -69,7 +83,7 @@ func SendAzureDeleteRequest(url string) (string, error) { return requestId[0], nil } -func SendAzureRequest(url string, requestType string, data []byte) (*http.Response, error) { +func SendAzureRequest(url string, requestType string, contentType string, data []byte) (*http.Response, error) { if len(url) == 0 { return nil, fmt.Errorf(paramNotSpecifiedError, "url") } @@ -79,7 +93,7 @@ func SendAzureRequest(url string, requestType string, data []byte) (*http.Respon client := createHttpClient() - response, err := sendRequest(client, url, requestType, data, 7) + response, err := sendRequest(client, url, requestType, contentType, data, 7) if err != nil { return nil, err } @@ -159,7 +173,7 @@ func CheckStringParams(url string) ([]byte, error) { return nil, fmt.Errorf(paramNotSpecifiedError, "url") } - response, err := SendAzureRequest(url, "GET", nil) + response, err := SendAzureRequest(url, "GET", "", nil) if err != nil { return nil, err } @@ -188,8 +202,8 @@ func NewUUID() (string, error) { //Region private methods starts -func sendRequest(client *http.Client, url string, requestType string, data []byte, numberOfRetries int) (*http.Response, error) { - request, reqErr := createAzureRequest(url, requestType, data) +func sendRequest(client *http.Client, url string, requestType string, contentType string, data []byte, numberOfRetries int) (*http.Response, error) { + request, reqErr := createAzureRequest(url, requestType, contentType, data) if reqErr != nil { return nil, reqErr } @@ -200,7 +214,7 @@ func sendRequest(client *http.Client, url string, requestType string, data []byt return nil, err } - return sendRequest(client, url, requestType, data, numberOfRetries-1) + return sendRequest(client, url, requestType, contentType, data, numberOfRetries-1) } if response.StatusCode > 299 { @@ -211,7 +225,7 @@ func sendRequest(client *http.Client, url string, requestType string, data []byt return nil, azureErr } - return sendRequest(client, url, requestType, data, numberOfRetries-1) + return sendRequest(client, url, requestType, contentType, data, numberOfRetries-1) } } @@ -228,7 +242,7 @@ func getAzureError(responseBody []byte) error { return error } -func createAzureRequest(url string, requestType string, data []byte) (*http.Request, error) { +func createAzureRequest(url string, requestType string, contentType string, data []byte) (*http.Request, error) { var request *http.Request var err error @@ -245,7 +259,11 @@ func createAzureRequest(url string, requestType string, data []byte) (*http.Requ } request.Header.Add(msVersionHeader, msVersionHeaderValue) - request.Header.Add(contentHeader, contentHeaderValue) + if len(contentType) > 0 { + request.Header.Add(contentHeader, contentType) + } else { + request.Header.Add(contentHeader, defaultContentHeaderValue) + } return request, nil }