Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Add Azure provider (peer-review PR) #2053

Merged
merged 14 commits into from
Jun 2, 2015
Merged
12 changes: 12 additions & 0 deletions builtin/bins/provider-azure/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

import (
"github.com/hashicorp/terraform/builtin/providers/azure"
"github.com/hashicorp/terraform/plugin"
)

func main() {
plugin.Serve(&plugin.ServeOpts{
ProviderFunc: azure.Provider,
})
}
1 change: 1 addition & 0 deletions builtin/bins/provider-azure/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package main
58 changes: 58 additions & 0 deletions builtin/providers/azure/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package azure

import (
"fmt"
"os"
"sync"

"github.com/svanharmelen/azure-sdk-for-go/management"
)

// Config is the configuration structure used to instantiate a
// new Azure management client.
type Config struct {
SettingsFile string
SubscriptionID string
Certificate []byte
ManagementURL string
}

// Client contains all the handles required for managing Azure services.
type Client struct {
// unfortunately; because of how Azure's network API works; doing networking operations
// concurrently is very hazardous, and we need a mutex to guard the management.Client.
mutex *sync.Mutex
mgmtClient management.Client
}

// NewClientFromSettingsFile returns a new Azure management
// client created using a publish settings file.
func (c *Config) NewClientFromSettingsFile() (*Client, error) {
if _, err := os.Stat(c.SettingsFile); os.IsNotExist(err) {
return nil, fmt.Errorf("Publish Settings file %q does not exist!", c.SettingsFile)
}

mc, err := management.ClientFromPublishSettingsFile(c.SettingsFile, c.SubscriptionID)
if err != nil {
return nil, nil
}

return &Client{
mutex: &sync.Mutex{},
mgmtClient: mc,
}, nil
}

// NewClient returns a new Azure management client created
// using a subscription ID and certificate.
func (c *Config) NewClient() (*Client, error) {
mc, err := management.NewClient(c.SubscriptionID, c.Certificate)
if err != nil {
return nil, nil
}

return &Client{
mutex: &sync.Mutex{},
mgmtClient: mc,
}, nil
}
68 changes: 68 additions & 0 deletions builtin/providers/azure/provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package azure

import (
"fmt"

"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
"github.com/mitchellh/go-homedir"
)

// Provider returns a terraform.ResourceProvider.
func Provider() terraform.ResourceProvider {
return &schema.Provider{
Schema: map[string]*schema.Schema{
"settings_file": &schema.Schema{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would have been nice to provide the id + certificate + url authentication option as well for people with Windows Azure Packs.

Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("AZURE_SETTINGS_FILE", nil),
},

"subscription_id": &schema.Schema{
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("AZURE_SUBSCRIPTION_ID", ""),
},

"certificate": &schema.Schema{
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("AZURE_CERTIFICATE", ""),
},
},

ResourcesMap: map[string]*schema.Resource{
"azure_data_disk": resourceAzureDataDisk(),
"azure_instance": resourceAzureInstance(),
"azure_security_group": resourceAzureSecurityGroup(),
"azure_virtual_network": resourceAzureVirtualNetwork(),
},

ConfigureFunc: providerConfigure,
}
}

func providerConfigure(d *schema.ResourceData) (interface{}, error) {
settingsFile, err := homedir.Expand(d.Get("settings_file").(string))
if err != nil {
return nil, err
}

config := Config{
SettingsFile: settingsFile,
SubscriptionID: d.Get("subscription_id").(string),
Certificate: []byte(d.Get("certificate").(string)),
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you do a homedir expand on the settings_file? Like we do over here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, will commit in a second...


if config.SettingsFile != "" {
return config.NewClientFromSettingsFile()
}

if config.SubscriptionID != "" && len(config.Certificate) > 0 {
return config.NewClient()
}

return nil, fmt.Errorf(
"Insufficient configuration data. Please specify either a 'settings_file'\n" +
"or both a 'subscription_id' and 'certificate'.")
}
45 changes: 45 additions & 0 deletions builtin/providers/azure/provider_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package azure

import (
"os"
"testing"

"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
)

var testAccProviders map[string]terraform.ResourceProvider
var testAccProvider *schema.Provider

func init() {
testAccProvider = Provider().(*schema.Provider)
testAccProviders = map[string]terraform.ResourceProvider{
"azure": testAccProvider,
}
}

func TestProvider(t *testing.T) {
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
t.Fatalf("err: %s", err)
}
}

func TestProvider_impl(t *testing.T) {
var _ terraform.ResourceProvider = Provider()
}

func testAccPreCheck(t *testing.T) {
if v := os.Getenv("AZURE_SETTINGS_FILE"); v == "" {
subscriptionID := os.Getenv("AZURE_SUBSCRIPTION_ID")
certificate := os.Getenv("AZURE_CERTIFICATE")

if subscriptionID == "" || certificate == "" {
t.Fatal("either AZURE_SETTINGS_FILE, or AZURE_SUBSCRIPTION_ID " +
"and AZURE_CERTIFICATE must be set for acceptance tests")
}
}

if v := os.Getenv("AZURE_STORAGE"); v == "" {
t.Fatal("AZURE_STORAGE must be set for acceptance tests")
}
}
Loading