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

resource_arm_sql_server: switch dependency from riviera to azure-sdk-for-go #189

Merged
merged 8 commits into from
Aug 18, 2017
7 changes: 7 additions & 0 deletions azurerm/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ type ArmClient struct {
keyVaultClient keyvault.VaultsClient

sqlElasticPoolsClient sql.ElasticPoolsClient
sqlServersClient sql.ServersClient

appInsightsClient appinsights.ComponentsClient

Expand Down Expand Up @@ -526,6 +527,12 @@ func (c *Config) getArmClient() (*ArmClient, error) {
sqlepc.Sender = autorest.CreateSender(withRequestLogging())
client.sqlElasticPoolsClient = sqlepc

sqlsrv := sql.NewServersClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&sqlsrv.Client)
sqlsrv.Authorizer = auth
sqlsrv.Sender = autorest.CreateSender(withRequestLogging())
client.sqlServersClient = sqlsrv

ai := appinsights.NewComponentsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&ai.Client)
ai.Authorizer = auth
Expand Down
147 changes: 76 additions & 71 deletions azurerm/resource_arm_sql_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,60 @@ package azurerm

import (
"fmt"
"log"

"github.com/Azure/azure-sdk-for-go/arm/sql"
"github.com/hashicorp/terraform/helper/schema"
"github.com/jen20/riviera/azure"
"github.com/jen20/riviera/sql"
"github.com/hashicorp/terraform/helper/validation"
)

func resourceArmSqlServer() *schema.Resource {
return &schema.Resource{
Create: resourceArmSqlServerCreate,
Create: resourceArmSqlServerCreateUpdate,
Read: resourceArmSqlServerRead,
Update: resourceArmSqlServerCreate,
Update: resourceArmSqlServerCreateUpdate,
Delete: resourceArmSqlServerDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"name": &schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"location": locationSchema(),

"resource_group_name": &schema.Schema{
"resource_group_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"version": &schema.Schema{
"version": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{
string(sql.TwoFullStopZero),
string(sql.OneTwoFullStopZero),
}, true),
// TODO: is this ForceNew?
},

"administrator_login": &schema.Schema{
"administrator_login": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"administrator_login_password": &schema.Schema{
"administrator_login_password": {
Type: schema.TypeString,
Required: true,
Sensitive: true,
},

"fully_qualified_domain_name": &schema.Schema{
"fully_qualified_domain_name": {
Type: schema.TypeString,
Computed: true,
},
Expand All @@ -60,101 +65,101 @@ func resourceArmSqlServer() *schema.Resource {
}
}

func resourceArmSqlServerCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient)
rivieraClient := client.rivieraClient
func resourceArmSqlServerCreateUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).sqlServersClient

name := d.Get("name").(string)
resGroup := d.Get("resource_group_name").(string)
location := d.Get("location").(string)
adminUsername := d.Get("administrator_login").(string)
adminPassword := d.Get("administrator_login_password").(string)
version := d.Get("version").(string)

tags := d.Get("tags").(map[string]interface{})
expandedTags := expandTags(tags)

createRequest := rivieraClient.NewRequest()
createRequest.Command = &sql.CreateOrUpdateServer{
Name: d.Get("name").(string),
Location: d.Get("location").(string),
ResourceGroupName: d.Get("resource_group_name").(string),
AdministratorLogin: azure.String(d.Get("administrator_login").(string)),
AdministratorLoginPassword: azure.String(d.Get("administrator_login_password").(string)),
Version: azure.String(d.Get("version").(string)),
Tags: *expandedTags,
metadata := expandTags(tags)

parameters := sql.Server{
Location: &location,
Copy link
Contributor

Choose a reason for hiding this comment

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

@sebastus I was doing some edge-case testing on this - we can't submit the FQDN since it's only returned as a Computed property (as such I've removed this)

Tags: metadata,
ServerProperties: &sql.ServerProperties{
Version: sql.ServerVersion(version),
AdministratorLogin: &adminUsername,
AdministratorLoginPassword: &adminPassword,
},
}

createResponse, err := createRequest.Execute()
response, err := client.CreateOrUpdate(resGroup, name, parameters)
if err != nil {
return fmt.Errorf("Error creating SQL Server: %s", err)
}
if !createResponse.IsSuccessful() {
return fmt.Errorf("Error creating SQL Server: %s", createResponse.Error)
}
// if the name is in-use, Azure returns a 409 "Unknown Service Error" which is a bad UX
if responseWasConflict(response.Response) {
return fmt.Errorf("SQL Server names need to be globally unique and '%s' is already in use.", name)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

@sebastus heads up that doing some edge-case testing I realised Azure returns a "409 Unknown Service Error" which isn't such a great UX, so I've added this to be more descriptive (appears the name needs to be globally unique as it's used in the FQDN)


readRequest := rivieraClient.NewRequest()
readRequest.Command = &sql.GetServer{
Name: d.Get("name").(string),
ResourceGroupName: d.Get("resource_group_name").(string),
return err
}

readResponse, err := readRequest.Execute()
if err != nil {
return fmt.Errorf("Error reading SQL Server: %s", err)
}
if !readResponse.IsSuccessful() {
return fmt.Errorf("Error reading SQL Server: %s", readResponse.Error)
if response.ID == nil {
return fmt.Errorf("Cannot create SQL Server %s (resource group %s) ID", name, resGroup)
}

resp := readResponse.Parsed.(*sql.GetServerResponse)
d.SetId(*resp.ID)
d.SetId(*response.ID)

return resourceArmSqlServerRead(d, meta)
}

func resourceArmSqlServerRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient)
rivieraClient := client.rivieraClient
client := meta.(*ArmClient).sqlServersClient

id, err := parseAzureResourceID(d.Id())
if err != nil {
return err
}

readRequest := rivieraClient.NewRequestForURI(d.Id())
readRequest.Command = &sql.GetServer{}
resGroup := id.ResourceGroup
name := id.Path["servers"]

readResponse, err := readRequest.Execute()
result, err := client.Get(resGroup, name)
if err != nil {
return fmt.Errorf("Error reading SQL Server: %s", err)
}
if !readResponse.IsSuccessful() {
log.Printf("[INFO] Error reading SQL Server %q - removing from state", d.Id())
d.SetId("")
return fmt.Errorf("Error reading SQL Server: %s", readResponse.Error)
if responseWasNotFound(result.Response) {
d.SetId("")
return nil
}
return fmt.Errorf("Error reading SQL Server %s: %v", name, err)
}

resp := readResponse.Parsed.(*sql.GetServerResponse)
d.Set("name", name)
d.Set("resource_group_name", resGroup)
d.Set("location", azureRMNormalizeLocation(*result.Location))

d.Set("name", id.Path["servers"])
d.Set("resource_group_name", id.ResourceGroup)
d.Set("location", azureRMNormalizeLocation(*resp.Location))
d.Set("fully_qualified_domain_name", resp.FullyQualifiedDomainName)
d.Set("administrator_login", resp.AdministratorLogin)
d.Set("version", resp.Version)
if serverProperties := result.ServerProperties; serverProperties != nil {
d.Set("version", string(serverProperties.Version))
d.Set("administrator_login", serverProperties.AdministratorLogin)
d.Set("fully_qualified_domain_name", serverProperties.FullyQualifiedDomainName)
}

flattenAndSetTags(d, resp.Tags)
flattenAndSetTags(d, result.Tags)

return nil
}

func resourceArmSqlServerDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient)
rivieraClient := client.rivieraClient

deleteRequest := rivieraClient.NewRequestForURI(d.Id())
deleteRequest.Command = &sql.DeleteServer{}
client := meta.(*ArmClient).sqlServersClient

deleteResponse, err := deleteRequest.Execute()
id, err := parseAzureResourceID(d.Id())
if err != nil {
return fmt.Errorf("Error deleting SQL Server: %s", err)
return err
}
if !deleteResponse.IsSuccessful() {
return fmt.Errorf("Error deleting SQL Server: %s", deleteResponse.Error)

resGroup := id.ResourceGroup
name := id.Path["servers"]

response, err := client.Delete(resGroup, name)
if err != nil {
if responseWasNotFound(response) {
return nil
}

return fmt.Errorf("Error deleting SQL Server %s: %+v", name, err)
}

return nil
Expand Down
43 changes: 24 additions & 19 deletions azurerm/resource_arm_sql_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"github.com/jen20/riviera/sql"
)

func TestAccAzureRMSqlServer_basic(t *testing.T) {
Expand Down Expand Up @@ -61,48 +60,54 @@ func TestAccAzureRMSqlServer_withTags(t *testing.T) {

func testCheckAzureRMSqlServerExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {

// Ensure we have enough information in state to look up in API
rs, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("Not found: %s", name)
}

conn := testAccProvider.Meta().(*ArmClient).rivieraClient

readRequest := conn.NewRequestForURI(rs.Primary.ID)
readRequest.Command = &sql.GetServer{}
sqlServerName := rs.Primary.Attributes["name"]
resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"]
if !hasResourceGroup {
return fmt.Errorf("Bad: no resource group found in state for SQL Server: %s", sqlServerName)
}

readResponse, err := readRequest.Execute()
conn := testAccProvider.Meta().(*ArmClient).sqlServersClient
resp, err := conn.Get(resourceGroup, sqlServerName)
if err != nil {
return fmt.Errorf("Bad: GetServer: %+v", err)
}
if !readResponse.IsSuccessful() {
return fmt.Errorf("Bad: GetServer: %+v", readResponse.Error)
if responseWasNotFound(resp.Response) {
return fmt.Errorf("Bad: SQL Server %s (resource group: %s) does not exist", sqlServerName, resourceGroup)
}
return fmt.Errorf("Bad: Get SQL Server: %v", err)
}

return nil
}
}

func testCheckAzureRMSqlServerDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*ArmClient).rivieraClient
conn := testAccProvider.Meta().(*ArmClient).sqlServersClient

for _, rs := range s.RootModule().Resources {
if rs.Type != "azurerm_sql_server" {
continue
}

readRequest := conn.NewRequestForURI(rs.Primary.ID)
readRequest.Command = &sql.GetServer{}
sqlServerName := rs.Primary.Attributes["name"]
resourceGroup := rs.Primary.Attributes["resource_group_name"]

resp, err := conn.Get(resourceGroup, sqlServerName)

readResponse, err := readRequest.Execute()
if err != nil {
return fmt.Errorf("Bad: GetServer: % +v", err)
}
if responseWasNotFound(resp.Response) {
return nil
}

if readResponse.IsSuccessful() {
return fmt.Errorf("Bad: SQL Server still exists: %+v", readResponse.Error)
return fmt.Errorf("Bad: Get Server: %+v", err)
}

return fmt.Errorf("SQL Server %s still exists", sqlServerName)

}

return nil
Expand Down
10 changes: 9 additions & 1 deletion azurerm/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,17 @@ import (
"github.com/Azure/go-autorest/autorest"
)

func responseWasConflict(resp autorest.Response) bool {
return responseWasStatusCode(resp, http.StatusConflict)
}

func responseWasNotFound(resp autorest.Response) bool {
return responseWasStatusCode(resp, http.StatusNotFound)
}

func responseWasStatusCode(resp autorest.Response, statusCode int) bool {
if r := resp.Response; r != nil {
if r.StatusCode == http.StatusNotFound {
if r.StatusCode == statusCode {
return true
}
}
Expand Down
Loading