diff --git a/pkg/resourcemanager/azuresql/azuresqldb/azuresqldb_reconcile.go b/pkg/resourcemanager/azuresql/azuresqldb/azuresqldb_reconcile.go index db505b1806b..e6947b01aa1 100644 --- a/pkg/resourcemanager/azuresql/azuresqldb/azuresqldb_reconcile.go +++ b/pkg/resourcemanager/azuresql/azuresqldb/azuresqldb_reconcile.go @@ -6,6 +6,7 @@ package azuresqldb import ( "context" "fmt" + "strings" azurev1alpha1 "github.com/Azure/azure-service-operator/api/v1alpha1" "github.com/Azure/azure-service-operator/pkg/errhelp" @@ -65,18 +66,16 @@ func (db *AzureSqlDbManager) Ensure(ctx context.Context, obj runtime.Object, opt instance.Status.Message = resourcemanager.SuccessMsg instance.Status.ResourceId = *dbGet.ID return true, nil - } else { - azerr := errhelp.NewAzureErrorAzureError(err) - ignore := []string{ - errhelp.NotFoundErrorCode, - errhelp.ResourceNotFound, - errhelp.ResourceGroupNotFoundErrorCode, - } - if !helpers.ContainsString(ignore, azerr.Type) { - instance.Status.Message = err.Error() - instance.Status.Provisioning = false - return false, fmt.Errorf("AzureSqlDb GetDB error %v", err) - } + } + instance.Status.Message = fmt.Sprintf("AzureSqlDb Get error %s", err.Error()) + azerr := errhelp.NewAzureErrorAzureError(err) + requeuErrors := []string{ + errhelp.ParentNotFoundErrorCode, + errhelp.ResourceGroupNotFoundErrorCode, + } + if helpers.ContainsString(requeuErrors, azerr.Type) { + instance.Status.Provisioning = false + return false, nil } resp, err := db.CreateOrUpdateDB(ctx, groupName, location, server, labels, azureSQLDatabaseProperties) @@ -100,6 +99,13 @@ func (db *AzureSqlDbManager) Ensure(ctx context.Context, obj runtime.Object, opt return false, nil } + // if the database is busy, requeue + errorString := err.Error() + if strings.Contains(errorString, "Try again later") { + instance.Status.Provisioning = false + return false, nil + } + // assertion that a 404 error implies that the Azure SQL server hasn't been provisioned yet if resp != nil && resp.StatusCode == 404 { instance.Status.Message = fmt.Sprintf("Waiting for SQL Server %s to provision", server) diff --git a/pkg/resourcemanager/azuresql/azuresqlfailovergroup/azuresqlfailovergroup_reconcile.go b/pkg/resourcemanager/azuresql/azuresqlfailovergroup/azuresqlfailovergroup_reconcile.go index 72f57c28171..4a32fe22bff 100644 --- a/pkg/resourcemanager/azuresql/azuresqlfailovergroup/azuresqlfailovergroup_reconcile.go +++ b/pkg/resourcemanager/azuresql/azuresqlfailovergroup/azuresqlfailovergroup_reconcile.go @@ -58,6 +58,15 @@ func (fg *AzureSqlFailoverGroupManager) Ensure(ctx context.Context, obj runtime. return true, nil } instance.Status.Message = fmt.Sprintf("AzureSqlFailoverGroup Get error %s", err.Error()) + requeuErrors := []string{ + errhelp.ResourceGroupNotFoundErrorCode, + errhelp.ParentNotFoundErrorCode, + } + azerr := errhelp.NewAzureErrorAzureError(err) + if helpers.ContainsString(requeuErrors, azerr.Type) { + instance.Status.Provisioning = false + return false, nil + } _, err = fg.CreateOrUpdateFailoverGroup(ctx, groupName, serverName, failoverGroupName, sqlFailoverGroupProperties) if err != nil { diff --git a/pkg/resourcemanager/azuresql/azuresqlfirewallrule/azuresqlfirewallrule_reconcile.go b/pkg/resourcemanager/azuresql/azuresqlfirewallrule/azuresqlfirewallrule_reconcile.go index f5503939ea8..e6b1002fb9b 100644 --- a/pkg/resourcemanager/azuresql/azuresqlfirewallrule/azuresqlfirewallrule_reconcile.go +++ b/pkg/resourcemanager/azuresql/azuresqlfirewallrule/azuresqlfirewallrule_reconcile.go @@ -37,6 +37,15 @@ func (fw *AzureSqlFirewallRuleManager) Ensure(ctx context.Context, obj runtime.O return true, nil } instance.Status.Message = fmt.Sprintf("AzureSqlFirewallRule Get error %s", err.Error()) + requeuErrors := []string{ + errhelp.ResourceGroupNotFoundErrorCode, + errhelp.ParentNotFoundErrorCode, + } + azerr := errhelp.NewAzureErrorAzureError(err) + if helpers.ContainsString(requeuErrors, azerr.Type) { + instance.Status.Provisioning = false + return false, nil + } _, err = fw.CreateOrUpdateSQLFirewallRule(ctx, groupName, server, ruleName, startIP, endIP) if err != nil { diff --git a/pkg/resourcemanager/azuresql/azuresqluser/azuresqluser_reconcile.go b/pkg/resourcemanager/azuresql/azuresqluser/azuresqluser_reconcile.go index 235838a30a0..649752a4d96 100644 --- a/pkg/resourcemanager/azuresql/azuresqluser/azuresqluser_reconcile.go +++ b/pkg/resourcemanager/azuresql/azuresqluser/azuresqluser_reconcile.go @@ -77,28 +77,44 @@ func (s *AzureSqlUserManager) Ensure(ctx context.Context, obj runtime.Object, op _, err = s.GetDB(ctx, instance.Spec.ResourceGroup, instance.Spec.Server, instance.Spec.DbName) if err != nil { - instance.Status.Message = err.Error() + instance.Status.Message = errhelp.StripErrorIDs(err) + instance.Status.Provisioning = false - catch := []string{ + requeuErrors := []string{ errhelp.ResourceNotFound, errhelp.ParentNotFoundErrorCode, errhelp.ResourceGroupNotFoundErrorCode, } azerr := errhelp.NewAzureErrorAzureError(err) - if helpers.ContainsString(catch, azerr.Type) { + if helpers.ContainsString(requeuErrors, azerr.Type) { return false, nil } - return false, err + + // if the database is busy, requeue + errorString := err.Error() + if strings.Contains(errorString, "Please retry the connection later") { + return false, nil + } + + // if this is an unmarshall error - igmore and continue, otherwise report error and requeue + if !strings.Contains(errorString, "cannot unmarshal array into Go struct field serviceError2.details") { + return false, err + } } db, err := s.ConnectToSqlDb(ctx, DriverName, instance.Spec.Server, instance.Spec.DbName, SqlServerPort, adminUser, adminPassword) if err != nil { instance.Status.Message = errhelp.StripErrorIDs(err) + instance.Status.Provisioning = false // catch firewall issue - keep cycling until it clears up if strings.Contains(err.Error(), "create a firewall rule for this IP address") { - instance.Status.Provisioned = false - instance.Status.Provisioning = false + return false, nil + } + + // if the database is busy, requeue + errorString := err.Error() + if strings.Contains(errorString, "Please retry the connection later") { return false, nil } diff --git a/pkg/resourcemanager/azuresql/azuresqlvnetrule/azuresqlvnetrule_reconcile.go b/pkg/resourcemanager/azuresql/azuresqlvnetrule/azuresqlvnetrule_reconcile.go index dc64bfb88df..2d43032eac8 100644 --- a/pkg/resourcemanager/azuresql/azuresqlvnetrule/azuresqlvnetrule_reconcile.go +++ b/pkg/resourcemanager/azuresql/azuresqlvnetrule/azuresqlvnetrule_reconcile.go @@ -6,6 +6,7 @@ package azuresqlvnetrule import ( "context" "fmt" + "strings" "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/2015-05-01-preview/sql" azurev1alpha1 "github.com/Azure/azure-service-operator/api/v1alpha1" @@ -43,6 +44,15 @@ func (vr *AzureSqlVNetRuleManager) Ensure(ctx context.Context, obj runtime.Objec return false, nil } instance.Status.Message = fmt.Sprintf("AzureSqlVNetRule Get error %s", err.Error()) + requeuErrors := []string{ + errhelp.ResourceGroupNotFoundErrorCode, + errhelp.ParentNotFoundErrorCode, + } + azerr := errhelp.NewAzureErrorAzureError(err) + if helpers.ContainsString(requeuErrors, azerr.Type) { + instance.Status.Provisioning = false + return false, nil + } instance.Status.Provisioning = true _, err = vr.CreateOrUpdateSQLVNetRule(ctx, groupName, server, ruleName, virtualNetworkRG, virtualnetworkname, subnetName, ignoreendpoint) @@ -66,6 +76,13 @@ func (vr *AzureSqlVNetRuleManager) Ensure(ctx context.Context, obj runtime.Objec return false, nil } + // this happens when we try to create the VNet rule and the server doesnt exist yet + errorString := err.Error() + if strings.Contains(errorString, "does not have the server") { + instance.Status.Provisioning = false + return false, nil + } + return false, err } diff --git a/pkg/util/util.go b/pkg/util/util.go deleted file mode 100644 index e85ed10f8e8..00000000000 --- a/pkg/util/util.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package util - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "log" -) - -// PrintAndLog writes to stdout and to a logger. -func PrintAndLog(message string) { - log.Println(message) - fmt.Println(message) -} - -func Contains(array []string, element string) bool { - for _, e := range array { - if e == element { - return true - } - } - return false -} - -// ReadJSON reads a json file, and unmashals it. -// Very useful for template deployments. -func ReadJSON(path string) (*map[string]interface{}, error) { - data, err := ioutil.ReadFile(path) - if err != nil { - log.Fatalf("failed to read template file: %v\n", err) - } - contents := make(map[string]interface{}) - json.Unmarshal(data, &contents) - return &contents, nil -}