Skip to content

Commit

Permalink
Added error handling for case where SQL server instance not found
Browse files Browse the repository at this point in the history
  • Loading branch information
aka-msft authored and frodopwns committed Oct 10, 2019
1 parent 0aac5e2 commit 7f39f0c
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 48 deletions.
3 changes: 2 additions & 1 deletion api/v1/sqlaction_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ type SqlActionStatus struct {
// Important: Run "make" to regenerate code after modifying this file
Provisioning bool `json:"provisioning,omitempty"`
Provisioned bool `json:"provisioned,omitempty"`
State string `json:"state,omitempty"`
Message string `json:"state,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status

// SqlAction is the Schema for the sqlactions API
type SqlAction struct {
Expand Down
2 changes: 2 additions & 0 deletions config/crd/bases/azure.microsoft.com_sqlactions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ spec:
kind: SqlAction
plural: sqlactions
scope: ""
subresources:
status: {}
validation:
openAPIV3Schema:
description: SqlAction is the Schema for the sqlactions API
Expand Down
120 changes: 73 additions & 47 deletions controllers/sqlaction_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@ func (r *SqlActionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
Requeue: true,
RequeueAfter: time.Second * time.Duration(requeueAfter),
}, nil
} else if errhelp.IsResourceNotFound(err) {
log.Info("Not requeueing as a specified resource (such as Sql Server instance) was not found")
instance.Status.Message = "Resource not found error"
// write information back to instance
if updateerr := r.Status().Update(ctx, &instance); updateerr != nil {
r.Recorder.Event(&instance, "Warning", "Failed", "Unable to update instance")
}
return ctrl.Result{}, nil
}
return ctrl.Result{}, fmt.Errorf("error reconciling sqlaction in azure: %v", err)
}
Expand Down Expand Up @@ -131,6 +139,11 @@ func (r *SqlActionReconciler) reconcileExternal(instance *azurev1.SqlAction) err
if instance.Status.Provisioned != true {

instance.Status.Provisioning = true
instance.Status.Message = "SqlAction in progress"
// write information back to instance
if updateerr := r.Status().Update(ctx, instance); updateerr != nil {
r.Recorder.Event(instance, "Warning", "Failed", "Unable to update instance")
}

sdkClient := sql.GoSDKClient{
Ctx: ctx,
Expand All @@ -140,77 +153,90 @@ func (r *SqlActionReconciler) reconcileExternal(instance *azurev1.SqlAction) err

sqlActionNamespacedName := types.NamespacedName{Name: name, Namespace: namespace}
if err := r.Get(ctx, sqlActionNamespacedName, instance); err != nil {
r.Log.Info("Unable to retrieve resource", "err", err.Error())
r.Log.Info("Unable to retrieve SqlAction resource", "err", err.Error())
// we'll ignore not-found errors, since they can't be fixed by an immediate
// requeue (we'll need to wait for a new notification), and we can get them
// on deleted requests.
return (err)
}

// Get the Sql Server instance that corresponds to the Server name in the spec for this action
server, err := sdkClient.GetServer(groupName, serverName)
server, err := sdkClient.GetServer()
if err != nil {
//log error and kill it, as the parent might not exist in the cluster. It could have been created elsewhere or through the portal directly
r.Recorder.Event(instance, "Warning", "Failed", "Unable to get instance of SqlServer")
r.Log.Info("Error", "Sql Server instance not found", err)
instance.Status.Message = "Sql Server instance not found"
return err
}

sdkClient.Location = *server.Location
sqlServerProperties := sql.SQLServerProperties{
AdministratorLogin: server.ServerProperties.AdministratorLogin,
AdministratorLoginPassword: server.ServerProperties.AdministratorLoginPassword,
}

sqlServerProperties.AdministratorLoginPassword = to.StringPtr(RollCreds(16))
if instance.Spec.ActionName == "rollcreds" {
sqlServerProperties := sql.SQLServerProperties{
AdministratorLogin: server.ServerProperties.AdministratorLogin,
AdministratorLoginPassword: server.ServerProperties.AdministratorLoginPassword,
}

//debugging
r.Log.Info("Info", "Username: ", *sqlServerProperties.AdministratorLogin)
r.Log.Info("Info", "New Password: ", *sqlServerProperties.AdministratorLoginPassword)
sqlServerProperties.AdministratorLoginPassword = to.StringPtr(RollCreds(16))

if _, err := sdkClient.CreateOrUpdateSQLServer(sqlServerProperties); err != nil {
if !strings.Contains(err.Error(), "not complete") {
r.Recorder.Event(instance, "Warning", "Failed", "Unable to provision or update instance")
return errhelp.NewAzureError(err)
//debugging
r.Log.Info("Info", "Username: ", *sqlServerProperties.AdministratorLogin)
r.Log.Info("Info", "New Password: ", *sqlServerProperties.AdministratorLoginPassword)

if _, err := sdkClient.CreateOrUpdateSQLServer(sqlServerProperties); err != nil {
if !strings.Contains(err.Error(), "not complete") {
r.Recorder.Event(instance, "Warning", "Failed", "Unable to provision or update instance")
return errhelp.NewAzureError(err)
}
} else {
r.Recorder.Event(instance, "Normal", "Provisioned", "resource request successfully submitted to Azure")
}
} else {
r.Recorder.Event(instance, "Normal", "Provisioned", "resource request successfully submitted to Azure")
}

// Update the k8s secret
secret := &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: serverName,
Namespace: namespace,
},
Data: map[string][]byte{
"username": []byte(*sqlServerProperties.AdministratorLogin),
"password": []byte(*sqlServerProperties.AdministratorLoginPassword),
"sqlservernamespace": []byte(instance.Namespace),
"sqlservername": []byte(name),
},
Type: "Opaque",
}
// Update the k8s secret
secret := &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: serverName,
Namespace: namespace,
},
Data: map[string][]byte{
"username": []byte(*sqlServerProperties.AdministratorLogin),
"password": []byte(*sqlServerProperties.AdministratorLoginPassword),
"sqlservernamespace": []byte(instance.Namespace),
"sqlservername": []byte(name),
},
Type: "Opaque",
}

result, createOrUpdateSecretErr := controllerutil.CreateOrUpdate(context.Background(), r.Client, secret, func() error {
r.Log.Info("mutating secret bundle")
secret.Data["password"] = []byte(*sqlServerProperties.AdministratorLoginPassword)
return nil
})
if createOrUpdateSecretErr != nil {
r.Log.Info("Error", "CreateOrUpdateSecretErr", createOrUpdateSecretErr)
return createOrUpdateSecretErr
}
result, createOrUpdateSecretErr := controllerutil.CreateOrUpdate(context.Background(), r.Client, secret, func() error {
r.Log.Info("mutating secret bundle")
secret.Data["password"] = []byte(*sqlServerProperties.AdministratorLoginPassword)
return nil
})
if createOrUpdateSecretErr != nil {
r.Log.Info("Error", "CreateOrUpdateSecretErr", createOrUpdateSecretErr)
return createOrUpdateSecretErr
}

// log result for debugging
r.Log.Info("Info", "OperationResult", result)
// log result for debugging
r.Log.Info("Info", "OperationResult", result)

instance.Status.Provisioning = false
instance.Status.Provisioned = true
instance.Status.Provisioning = false
instance.Status.Provisioned = true
instance.Status.Message = "SqlAction completed successfully."

// write information back to instance
if updateerr := r.Update(ctx, instance); updateerr != nil {
r.Recorder.Event(instance, "Warning", "Failed", "Unable to update instance")
// write information back to instance
if updateerr := r.Status().Update(ctx, instance); updateerr != nil {
r.Recorder.Event(instance, "Warning", "Failed", "Unable to update instance")
}

// write information back to instance
if updateerr := r.Update(ctx, instance); updateerr != nil {
r.Recorder.Event(instance, "Warning", "Failed", "Unable to update instance")
}
}

// Add other actions here (instance.Spec.ActionName)
}

return nil
Expand Down
5 changes: 5 additions & 0 deletions pkg/errhelp/errhelp.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,8 @@ func IsAsynchronousOperationNotComplete(err error) bool {
func IsStatusCode204(err error) bool {
return strings.Contains(err.Error(), "StatusCode=204")
}

// IsResourceNotFound checks if error reports that a referenced resource is not found
func IsResourceNotFound(err error) bool {
return strings.Contains(err.Error(), "ResourceNotFound")
}

0 comments on commit 7f39f0c

Please sign in to comment.