Skip to content

Commit

Permalink
Improve error handling
Browse files Browse the repository at this point in the history
To follow best practices for error and exception handling in Go and to prevent regressions,
err113 and gosec checks in golang-ci-linter are now enabled.
Errors now use API errors from k8s.io/apimachinery and predefined messages for status updates.
  • Loading branch information
mrkisaolamb committed Jan 10, 2025
1 parent e5a56f9 commit 05ccd22
Show file tree
Hide file tree
Showing 14 changed files with 54 additions and 38 deletions.
3 changes: 3 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@ linters:
- ginkgolinter
- gofmt
- govet
- gosec
- errname
- err113
run:
timeout: 5m
6 changes: 6 additions & 0 deletions api/v1beta1/conditions.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ const (

// Common Messages used by API objects.
const (
//NovaNetworkAttachmentsReadyInitMessage
NovaNetworkAttachmentsReadyErrorMessage = "NetworkAttachments error occurred not all pods have interfaces with ips as configured in NetworkAttachments: %s"

// NovaAPIReadyInitMessage
NovaAPIReadyInitMessage = "NovaAPI not started"

Expand Down Expand Up @@ -172,4 +175,7 @@ const (

//CellHostDiscoverErrorMessage
CellHostDiscoverErrorMessage = "CellHostDiscover error occurred %s"

//InputReadyErrorMessage
InputReadyErrorMessage = "Input data error occurred %s"
)
15 changes: 8 additions & 7 deletions controllers/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ const (

// fields to index to reconcile when change
passwordSecretField = ".spec.secret"
caBundleSecretNameField = ".spec.tls.caBundleSecretName"
caBundleSecretNameField = ".spec.tls.caBundleSecretName" // #nosec G101
tlsAPIInternalField = ".spec.tls.api.internal.secretName"
tlsAPIPublicField = ".spec.tls.api.public.secretName"
tlsMetadataField = ".spec.tls.secretName"
Expand Down Expand Up @@ -186,8 +186,6 @@ type conditionUpdater interface {
MarkTrue(t condition.Type, messageFormat string, messageArgs ...interface{})
}

// ensureSecret - ensures that the Secret object exists and the expected fields
// are in the Secret. It returns a hash of the values of the expected fields.
func ensureSecret(
ctx context.Context,
secretName types.NamespacedName,
Expand Down Expand Up @@ -225,7 +223,10 @@ func ensureSecret(
for _, field := range expectedFields {
val, ok := secret.Data[field]
if !ok {
err := fmt.Errorf("field '%s' not found in secret/%s", field, secretName.Name)
// Usage in the code
err := k8s_errors.NewBadRequest(fmt.Sprintf("field '%s' not found in secret/%s", field, secretName.Name))
// ensureSecret - ensures that the Secret object exists and the expected fields
// are in the Secret. It returns a hash of the values of the expected fields.
conditionUpdater.Set(condition.FalseCondition(
condition.InputReadyCondition,
condition.ErrorReason,
Expand Down Expand Up @@ -579,7 +580,7 @@ func getNovaClient(
return nil, err
}
if (ctrlResult != ctrl.Result{}) {
return nil, fmt.Errorf("the CABundleSecret %s not found", auth.GetCABundleSecretName())
return nil, fmt.Errorf("the CABundleSecret %s not found: %w", auth.GetCABundleSecretName(), err)
}

tlsConfig = &openstack.TLSConfig{
Expand Down Expand Up @@ -641,7 +642,7 @@ func ensureMemcached(
condition.RequestedReason,
condition.SeverityInfo,
condition.MemcachedReadyWaitingMessage))
return nil, fmt.Errorf("memcached %s not found", memcachedName)
return nil, fmt.Errorf("%w: memcached %s not found", err, memcachedName)
}
conditionUpdater.Set(condition.FalseCondition(
condition.MemcachedReadyCondition,
Expand All @@ -658,7 +659,7 @@ func ensureMemcached(
condition.RequestedReason,
condition.SeverityInfo,
condition.MemcachedReadyWaitingMessage))
return nil, fmt.Errorf("memcached %s is not ready", memcachedName)
return nil, fmt.Errorf("%w: memcached %s is not ready", ErrResourceIsNotReady, memcachedName)
}
conditionUpdater.MarkTrue(condition.MemcachedReadyCondition, condition.MemcachedReadyMessage)

Expand Down
12 changes: 12 additions & 0 deletions controllers/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package controllers

import (
"errors"
)

var (
ErrResourceIsNotReady = errors.New("Resource is not ready")
ErrInvalidStatus = errors.New("invalid status")
ErrCannotUpdateObject = errors.New("cannot update object")
ErrFieldNotFound = errors.New("field not found in Secret")
)
14 changes: 7 additions & 7 deletions controllers/nova_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ func (r *NovaReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resul
case nova.DBCompleted:
instance.Status.Conditions.MarkTrue(novav1.NovaAPIDBReadyCondition, condition.DBReadyMessage)
default:
return ctrl.Result{}, fmt.Errorf("invalid DatabaseStatus from ensureAPIDB: %d", apiDBStatus)
return ctrl.Result{}, fmt.Errorf("%w from ensureAPIDB: %d", ErrInvalidStatus, apiDBStatus)
}

// We need to create a list of cellNames to iterate on and as the map
Expand Down Expand Up @@ -332,7 +332,7 @@ func (r *NovaReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resul
creatingDBs = append(creatingDBs, cellName)
case nova.DBCompleted:
default:
return ctrl.Result{}, fmt.Errorf("invalid DatabaseStatus from ensureCellDB: %d for cell %s", status, cellName)
return ctrl.Result{}, fmt.Errorf("%w from ensureCellDB: %d for cell %s", ErrInvalidStatus, status, cellName)
}
cellDBs[cellName] = &nova.Database{Database: cellDB, Status: status}
}
Expand Down Expand Up @@ -380,7 +380,7 @@ func (r *NovaReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resul
instance.Status.Conditions.MarkTrue(
novav1.NovaAPIMQReadyCondition, novav1.NovaAPIMQReadyMessage)
default:
return ctrl.Result{}, fmt.Errorf("invalid MessageBusStatus from for the API MQ: %d", apiMQStatus)
return ctrl.Result{}, fmt.Errorf("%w from for the API MQ: %d", ErrInvalidStatus, apiMQStatus)
}

cellMQs := map[string]*nova.MessageBus{}
Expand Down Expand Up @@ -408,7 +408,7 @@ func (r *NovaReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resul
creatingMQs = append(creatingMQs, cellName)
case nova.MQCompleted:
default:
return ctrl.Result{}, fmt.Errorf("invalid MessageBusStatus from ensureMQ: %d for cell %s", status, cellName)
return ctrl.Result{}, fmt.Errorf("%w from ensureMQ: %d for cell %s", ErrInvalidStatus, status, cellName)
}
cellMQs[cellName] = &nova.MessageBus{TransportURL: cellTransportURL, Status: status}
}
Expand Down Expand Up @@ -1631,8 +1631,8 @@ func (r *NovaReconciler) ensureMQ(

url, ok := secret.Data[TransportURLSelector]
if !ok {
return "", nova.MQFailed, fmt.Errorf(
"the TransportURL secret %s does not have 'transport_url' field", transportURL.Status.SecretName)
return "", nova.MQFailed, k8s_errors.NewBadRequest(fmt.Sprintf(
"the TransportURL secret %s does not have 'transport_url' field", transportURL.Status.SecretName))
}

return string(url), nova.MQCompleted, nil
Expand Down Expand Up @@ -1673,7 +1673,7 @@ func (r *NovaReconciler) ensureMetadata(
// If it is not created by us, we don't touch it
if !k8s_errors.IsNotFound(err) && !OwnedBy(metadata, instance) {
err := fmt.Errorf(
"cannot update NovaMetadata/%s as the cell is not owning it", metadata.Name)
"%w NovaMetadata/%s as the cell is not owning it", ErrCannotUpdateObject, metadata.Name)
Log.Error(err,
"NovaMetadata is enabled, but there is a "+
"NovaMetadata CR not owned by us. We cannot update it. "+
Expand Down
5 changes: 2 additions & 3 deletions controllers/novaapi_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -588,13 +588,12 @@ func (r *NovaAPIReconciler) ensureDeployment(
if networkReady {
instance.Status.Conditions.MarkTrue(condition.NetworkAttachmentsReadyCondition, condition.NetworkAttachmentsReadyMessage)
} else {
err := fmt.Errorf("not all pods have interfaces with ips as configured in NetworkAttachments: %s", instance.Spec.NetworkAttachments)
instance.Status.Conditions.Set(condition.FalseCondition(
condition.NetworkAttachmentsReadyCondition,
condition.ErrorReason,
condition.SeverityWarning,
condition.NetworkAttachmentsReadyErrorMessage,
err.Error()))
novav1.NovaNetworkAttachmentsReadyErrorMessage,
instance.Spec.NetworkAttachments))

return ctrl.Result{}, err
}
Expand Down
6 changes: 3 additions & 3 deletions controllers/novacell_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ func (r *NovaCellReconciler) ensureNoVNCProxy(
// If it is not created by us, we don't touch it
if !k8s_errors.IsNotFound(err) && !OwnedBy(novncproxy, instance) {
err := fmt.Errorf(
"cannot update NovaNoVNCProxy/%s as the cell is not owning it", novncproxyName.Name)
"%w NovaNoVNCProxy/%s as the cell is not owning it", ErrCannotUpdateObject, novncproxyName.Name)
Log.Error(err,
"NovaNoVNCProxy is enabled in this cell, but there is a "+
"NovaNoVNCProxy CR not owned by the cell. We cannot update it. "+
Expand Down Expand Up @@ -548,7 +548,7 @@ func (r *NovaCellReconciler) ensureMetadata(
// If it is not created by us, we don't touch it
if !k8s_errors.IsNotFound(err) && !OwnedBy(metadata, instance) {
err := fmt.Errorf(
"cannot update NovaMetadata/%s as the cell is not owning it", metadata.Name)
"%w NovaMetadata/%s as the cell is not owning it", ErrCannotUpdateObject, metadata.Name)
Log.Error(err,
"NovaMetadata is enabled, but there is a "+
"NovaMetadata CR not owned by us. We cannot update it. "+
Expand Down Expand Up @@ -708,7 +708,7 @@ func (r *NovaCellReconciler) ensureNovaCompute(
// If it is not created by us, we don't touch it
if !k8s_errors.IsNotFound(err) && !OwnedBy(novacompute, instance) {
err := fmt.Errorf(
"cannot update NovaCompute/%s as the cell is not owning it", novacompute.Name)
"%w NovaCompute/%s as the cell is not owning it", ErrCannotUpdateObject, novacompute.Name)
Log.Error(err,
"NovaCompute is defined in the cell, but there is a "+
"NovaCompute CR not owned by us. We cannot update it. "+
Expand Down
5 changes: 2 additions & 3 deletions controllers/novacompute_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -403,13 +403,12 @@ func (r *NovaComputeReconciler) ensureDeployment(
if networkReady {
instance.Status.Conditions.MarkTrue(condition.NetworkAttachmentsReadyCondition, condition.NetworkAttachmentsReadyMessage)
} else {
err := fmt.Errorf("not all pods have interfaces with ips as configured in NetworkAttachments: %s", instance.Spec.NetworkAttachments)
instance.Status.Conditions.Set(condition.FalseCondition(
condition.NetworkAttachmentsReadyCondition,
condition.ErrorReason,
condition.SeverityWarning,
condition.NetworkAttachmentsReadyErrorMessage,
err.Error()))
novav1.NovaNetworkAttachmentsReadyErrorMessage,
instance.Spec.NetworkAttachments))

return ctrl.Result{}, err
}
Expand Down
5 changes: 2 additions & 3 deletions controllers/novaconductor_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -560,13 +560,12 @@ func (r *NovaConductorReconciler) ensureDeployment(
if networkReady {
instance.Status.Conditions.MarkTrue(condition.NetworkAttachmentsReadyCondition, condition.NetworkAttachmentsReadyMessage)
} else {
err := fmt.Errorf("not all pods have interfaces with ips as configured in NetworkAttachments: %s", instance.Spec.NetworkAttachments)
instance.Status.Conditions.Set(condition.FalseCondition(
condition.NetworkAttachmentsReadyCondition,
condition.ErrorReason,
condition.SeverityWarning,
condition.NetworkAttachmentsReadyErrorMessage,
err.Error()))
novav1.NovaNetworkAttachmentsReadyErrorMessage,
instance.Spec.NetworkAttachments))

return ctrl.Result{}, err
}
Expand Down
5 changes: 2 additions & 3 deletions controllers/novametadata_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -598,13 +598,12 @@ func (r *NovaMetadataReconciler) ensureDeployment(
if networkReady {
instance.Status.Conditions.MarkTrue(condition.NetworkAttachmentsReadyCondition, condition.NetworkAttachmentsReadyMessage)
} else {
err := fmt.Errorf("not all pods have interfaces with ips as configured in NetworkAttachments: %s", instance.Spec.NetworkAttachments)
instance.Status.Conditions.Set(condition.FalseCondition(
condition.NetworkAttachmentsReadyCondition,
condition.ErrorReason,
condition.SeverityWarning,
condition.NetworkAttachmentsReadyErrorMessage,
err.Error()))
novav1.NovaNetworkAttachmentsReadyErrorMessage,
instance.Spec.NetworkAttachments))

return ctrl.Result{}, err
}
Expand Down
5 changes: 2 additions & 3 deletions controllers/novanovncproxy_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -546,13 +546,12 @@ func (r *NovaNoVNCProxyReconciler) ensureDeployment(
if networkReady {
instance.Status.Conditions.MarkTrue(condition.NetworkAttachmentsReadyCondition, condition.NetworkAttachmentsReadyMessage)
} else {
err := fmt.Errorf("not all pods have interfaces with ips as configured in NetworkAttachments: %s", instance.Spec.NetworkAttachments)
instance.Status.Conditions.Set(condition.FalseCondition(
condition.NetworkAttachmentsReadyCondition,
condition.ErrorReason,
condition.SeverityWarning,
condition.NetworkAttachmentsReadyErrorMessage,
err.Error()))
novav1.NovaNetworkAttachmentsReadyErrorMessage,
instance.Spec.NetworkAttachments))

return ctrl.Result{}, err
}
Expand Down
5 changes: 2 additions & 3 deletions controllers/novascheduler_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -613,13 +613,12 @@ func (r *NovaSchedulerReconciler) ensureDeployment(
if networkReady {
instance.Status.Conditions.MarkTrue(condition.NetworkAttachmentsReadyCondition, condition.NetworkAttachmentsReadyMessage)
} else {
err := fmt.Errorf("not all pods have interfaces with ips as configured in NetworkAttachments: %s", instance.Spec.NetworkAttachments)
instance.Status.Conditions.Set(condition.FalseCondition(
condition.NetworkAttachmentsReadyCondition,
condition.ErrorReason,
condition.SeverityWarning,
condition.NetworkAttachmentsReadyErrorMessage,
err.Error()))
novav1.NovaNetworkAttachmentsReadyErrorMessage,
instance.Spec.NetworkAttachments))

return ctrl.Result{}, err
}
Expand Down
4 changes: 2 additions & 2 deletions test/functional/novacell_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ var _ = Describe("NovaCell controller", func() {
corev1.ConditionFalse,
condition.ErrorReason,
fmt.Sprintf(
"NovaNoVNCProxy error occurred cannot update "+
"NovaNoVNCProxy error occurred cannot update object "+
"NovaNoVNCProxy/%s as the cell is not owning it",
cell2.NoVNCProxyName.Name,
),
Expand Down Expand Up @@ -833,7 +833,7 @@ var _ = Describe("NovaCell controller", func() {
corev1.ConditionFalse,
condition.ErrorReason,
fmt.Sprintf(
"NovaMetadata error occurred cannot update "+
"NovaMetadata error occurred cannot update object "+
"NovaMetadata/%s as the cell is not owning it",
cell2.MetadataName.Name,
),
Expand Down
2 changes: 1 addition & 1 deletion test/functional/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ var _ = BeforeSuite(func() {
dialer := &net.Dialer{Timeout: time.Duration(10) * time.Second}
addrPort := fmt.Sprintf("%s:%d", webhookInstallOptions.LocalServingHost, webhookInstallOptions.LocalServingPort)
Eventually(func() error {
conn, err := tls.DialWithDialer(dialer, "tcp", addrPort, &tls.Config{InsecureSkipVerify: true})
conn, err := tls.DialWithDialer(dialer, "tcp", addrPort, &tls.Config{InsecureSkipVerify: true}) // #nosec G402
if err != nil {
return err
}
Expand Down

0 comments on commit 05ccd22

Please sign in to comment.