Skip to content

Commit

Permalink
Populate syncthing errors to the user (#1168)
Browse files Browse the repository at this point in the history
* Populate syncthing errors to the user

Signed-off-by: Pablo Chico de Guzman <pchico83@gmail.com>

* PR comments

Signed-off-by: Pablo Chico de Guzman <pchico83@gmail.com>
  • Loading branch information
pchico83 committed Nov 18, 2020
1 parent 3213875 commit 2557bc0
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 82 deletions.
6 changes: 3 additions & 3 deletions cmd/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func Exec() *cobra.Command {
if errors.IsNotFound(err) {
return errors.UserError{
E: fmt.Errorf("Development container not found in namespace %s", dev.Namespace),
Hint: "Run `okteto up` to launch it or use `okteto namespace` to select the correct namespace and try again",
Hint: "Run 'okteto up' to launch it or use 'okteto namespace' to select the correct namespace and try again",
}
}

Expand Down Expand Up @@ -99,7 +99,7 @@ func executeExec(ctx context.Context, dev *model.Dev, args []string) error {
if p == nil {
return errors.UserError{
E: fmt.Errorf("development mode is not enabled on your deployment"),
Hint: "Run `okteto up` to enable it and try again",
Hint: "Run 'okteto up' to enable it and try again",
}
}

Expand All @@ -115,7 +115,7 @@ func executeExec(ctx context.Context, dev *model.Dev, args []string) error {
log.Infof("failed to get the SSH port for %s: %s", dev.Name, err)
return errors.UserError{
E: fmt.Errorf("development mode is not enabled on your deployment"),
Hint: "Run `okteto up` to enable it and try again",
Hint: "Run 'okteto up' to enable it and try again",
}
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/pipeline/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ func getCurrentNamespace(ctx context.Context) (string, error) {
log.Infof("couldn't get the current namespace: %s", err)
return "", errors.UserError{
E: fmt.Errorf("couldn't get the current namespace"),
Hint: "Run `okteto namespace`, or use the `--namespace` parameter",
Hint: "Run 'okteto namespace', or use the '--namespace' parameter",
}
}

Expand All @@ -192,7 +192,7 @@ func getCurrentNamespace(ctx context.Context) (string, error) {
if !namespaces.IsOktetoNamespace(ns) {
return "", errors.UserError{
E: fmt.Errorf("your current namespace '%s' is not managed by okteto", namespace),
Hint: "Run `okteto namespace`, or use the `--namespace` parameter",
Hint: "Run 'okteto namespace', or use the '--namespace' parameter",
}
}

Expand Down
68 changes: 50 additions & 18 deletions cmd/up/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,8 +324,12 @@ func (up *upContext) activate(isRetry, autoDeploy, build bool) error {

if deployments.IsDevModeOn(d) && deployments.HasBeenChanged(d) {
return errors.UserError{
E: fmt.Errorf("Deployment '%s' has been modified while your development container was active", d.Name),
Hint: "Follow these steps:\n 1. Execute 'okteto down'\n 2. Apply your manifest changes again: 'kubectl apply'\n 3. Execute 'okteto up' again\n More information is available here: https://okteto.com/docs/reference/known-issues/index.html#kubectl-apply-changes-are-undone-by-okteto-up",
E: fmt.Errorf("Deployment '%s' has been modified while your development container was active", d.Name),
Hint: `Follow these steps:
1. Execute 'okteto down'
2. Apply your manifest changes again: 'kubectl apply'
3. Execute 'okteto up' again
More information is available here: https://okteto.com/docs/reference/known-issues/index.html#kubectl-apply-changes-are-undone-by-okteto-up`,
}
}

Expand Down Expand Up @@ -424,10 +428,7 @@ func (up *upContext) shouldRetry(ctx context.Context, err error) bool {
case errors.ErrLostSyncthing:
return true
case errors.ErrCommandFailed:
if up.Sy.Ping(ctx, false) {
return false
}
return true
return !up.Sy.Ping(ctx, false)
}

return false
Expand All @@ -450,7 +451,7 @@ func (up *upContext) getCurrentDeployment(ctx context.Context, autoDeploy, isRet
if err == errors.ErrNotFound {
err = errors.UserError{
E: fmt.Errorf("Didn't find a deployment in namespace %s that matches the labels in your Okteto manifest", up.Dev.Namespace),
Hint: "Update your labels or use `okteto namespace` to select a different namespace and try again"}
Hint: "Update your labels or use 'okteto namespace' to select a different namespace and try again"}
}
return nil, false, err
}
Expand Down Expand Up @@ -479,6 +480,9 @@ func (up *upContext) waitUntilExitOrInterrupt() error {
return nil

case err := <-up.Disconnect:
if err == errors.ErrInsufficientSpace {
return up.getInsufficientSpaceError(err)
}
return err
}
}
Expand Down Expand Up @@ -819,14 +823,20 @@ func (up *upContext) synchronizeFiles(ctx context.Context) error {
}()

if err := up.Sy.WaitForCompletion(ctx, up.Dev, reporter); err != nil {
if err == errors.ErrUnknownSyncError {
analytics.TrackSyncError()
analytics.TrackSyncError()
switch err {
case errors.ErrLostSyncthing, errors.ErrResetSyncthing:
return err
case errors.ErrInsufficientSpace:
return up.getInsufficientSpaceError(err)
default:
return errors.UserError{
E: err,
Hint: `Help us improve okteto by filing an issue in https://github.com/okteto/okteto/issues/new.\n Please include the file generated by 'okteto doctor' if possible.\n Then, try to run 'okteto down -v' + 'okteto up' again`,
E: err,
Hint: `Help us improve okteto by filing an issue in https://github.com/okteto/okteto/issues/new.
Please include the file generated by 'okteto doctor' if possible.
Then, try to run 'okteto down -v' + 'okteto up' again`,
}
}
return err
}

// render to 100
Expand Down Expand Up @@ -903,8 +913,9 @@ func (up *upContext) checkOktetoStartError(ctx context.Context, msg string) erro
if up.Dev.PersistentVolumeEnabled() {
if userID != -1 && userID != *up.Dev.SecurityContext.RunAsUser {
return errors.UserError{
E: fmt.Errorf("User %d doesn't have write permissions for the %s directory", userID, up.Dev.MountPath),
Hint: fmt.Sprintf("Set 'securityContext.runAsUser: %d' in your okteto manifest\n After that, run 'okteto down -v' to reset your development container and run 'okteto up' again", userID),
E: fmt.Errorf("User %d doesn't have write permissions for the %s directory", userID, up.Dev.MountPath),
Hint: fmt.Sprintf(`Set 'securityContext.runAsUser: %d' in your okteto manifest.
After that, run 'okteto down -v' to reset your development container and run 'okteto up' again`, userID),
}
}
} else {
Expand All @@ -915,13 +926,16 @@ func (up *upContext) checkOktetoStartError(ctx context.Context, msg string) erro

if len(up.Dev.Secrets) > 0 {
return errors.UserError{
E: fmt.Errorf(msg),
Hint: fmt.Sprintf("Check your development container logs for errors: 'kubectl logs %s'\n Check that your container can write to the destination path of your secrets\n Run 'okteto down -v' to reset your development container and try again.", up.Pod),
E: fmt.Errorf(msg),
Hint: fmt.Sprintf(`Check your development container logs for errors: 'kubectl logs %s',
Check that your container can write to the destination path of your secrets.
Run 'okteto down -v' to reset your development container and try again`, up.Pod),
}
}
return errors.UserError{
E: fmt.Errorf(msg),
Hint: fmt.Sprintf("Check your development container logs for errors: 'kubectl logs %s'\n Run 'okteto down -v' to reset your development container and try again.", up.Pod),
E: fmt.Errorf(msg),
Hint: fmt.Sprintf(`Check your development container logs for errors: 'kubectl logs %s'.
Run 'okteto down -v' to reset your development container and try again`, up.Pod),
}
}

Expand Down Expand Up @@ -960,6 +974,24 @@ func (up *upContext) getInteractive() bool {
return false
}

func (up *upContext) getInsufficientSpaceError(err error) error {
if up.Dev.PersistentVolumeEnabled() {
return errors.UserError{
E: err,
Hint: `Okteto volume is full.
Increase your persistent volume size, run 'okteto down -v' and try 'okteto up' again.
More information about configuring your persistent volume at https://okteto.com/docs/reference/manifest#persistentvolume-object-optional`,
}
}
return errors.UserError{
E: err,
Hint: `The synchronization service is running out of space.
Enable persistent volumes in your okteto manifest and try again.
More information about configuring your persistent volume at https://okteto.com/docs/reference/manifest#persistentvolume-object-optional`,
}

}

// Shutdown runs the cancellation sequence. It will wait for all tasks to finish for up to 500 milliseconds
func (up *upContext) shutdown() {
if up.isTerm {
Expand Down
2 changes: 1 addition & 1 deletion cmd/utils/dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ func AskIfDeploy(name, namespace string) error {
if !deploy {
return errors.UserError{
E: fmt.Errorf("Deployment %s doesn't exist in namespace %s", name, namespace),
Hint: "Deploy your application first or use `okteto namespace` to select a different namespace and try again",
Hint: "Deploy your application first or use 'okteto namespace' to select a different namespace and try again",
}
}
return nil
Expand Down
5 changes: 4 additions & 1 deletion pkg/cmd/build/buildkit.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,10 @@ func getBuildkitClient(ctx context.Context, isOktetoCluster bool, buildKitHost s
c, err := getClientForOktetoCluster(ctx, buildKitHost)
if err != nil {
log.Infof("failed to create okteto build client: %s", err)
return nil, okErrors.UserError{E: fmt.Errorf("failed to create okteto build client"), Hint: okErrors.ErrNotLogged.Error()}
return nil, okErrors.UserError{
E: fmt.Errorf("failed to create okteto build client"),
Hint: okErrors.ErrNotLogged.Error(),
}
}

return c, nil
Expand Down
6 changes: 3 additions & 3 deletions pkg/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ var (
// ErrSSHConnectError is returned when okteto cannot connect to ssh
ErrSSHConnectError = fmt.Errorf("ssh start error")

// ErrUnknownSyncError is returned when syncthing reports an unknown sync error
ErrUnknownSyncError = fmt.Errorf("Unknown syncthing error")

// ErrNotInDevContainer is returned when an unsupported command is invoked from a dev container (e.g. okteto up)
ErrNotInDevContainer = fmt.Errorf("this command is not supported from inside an development container")

// ErrResetSyncthing is raised when syncthing database must be reset
ErrResetSyncthing = fmt.Errorf("synchronization database corrupted")

// ErrInsufficientSpace is raised when syncthing fails with no space available
ErrInsufficientSpace = fmt.Errorf("there isn't enough disk space available to synchronize your files")

// ErrBusySyncthing is raised when syncthing is busy
ErrBusySyncthing = fmt.Errorf("synchronization service is unresponsive")

Expand Down
11 changes: 1 addition & 10 deletions pkg/syncthing/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (s *Syncthing) Monitor(ctx context.Context, disconnect chan error) {

// MonitorStatus will send a message to disconnected if there is a synchronization error
func (s *Syncthing) MonitorStatus(ctx context.Context, disconnect chan error) {
ticker := time.NewTicker(300 * time.Second)
ticker := time.NewTicker(30 * time.Second)
for {
select {
case <-ticker.C:
Expand Down Expand Up @@ -82,15 +82,6 @@ func (s *Syncthing) checkLocalAndRemoteStatus(ctx context.Context) error {

func (s *Syncthing) checkStatus(ctx context.Context, local bool) error {
for _, folder := range s.Folders {
status, err := s.GetStatus(ctx, &folder, local)
if err != nil {
log.Infof("error getting status from path:%s local=%t", folder.LocalPath, local)
return err
}
if status.PullErrors == 0 {
continue
}

if err := s.GetFolderErrors(ctx, &folder, local); err != nil {
return err
}
Expand Down
54 changes: 10 additions & 44 deletions pkg/syncthing/syncthing.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import (

"github.com/okteto/okteto/pkg/config"
"github.com/okteto/okteto/pkg/errors"
okerr "github.com/okteto/okteto/pkg/errors"
"github.com/okteto/okteto/pkg/log"
"github.com/okteto/okteto/pkg/model"
"golang.org/x/crypto/bcrypt"
Expand Down Expand Up @@ -394,7 +393,7 @@ func (s *Syncthing) ResetDatabase(ctx context.Context, dev *model.Dev, local boo
if err != nil {
log.Infof("error posting 'rest/system/reset' local=%t syncthing API: %s", local, err)
if strings.Contains(err.Error(), "Client.Timeout") {
return errors.ErrUnknownSyncError
return fmt.Errorf("error resetting syncthing database local=%t: %s", local, err.Error())
}
return errors.ErrLostSyncthing
}
Expand Down Expand Up @@ -482,7 +481,6 @@ func (s *Syncthing) WaitForCompletion(ctx context.Context, dev *model.Dev, repor
ticker := time.NewTicker(500 * time.Millisecond)
for _, folder := range s.Folders {
log.Infof("waiting for synchronization to complete path=%s", folder.LocalPath)
retries := 0
for {
select {
case <-ticker.C:
Expand Down Expand Up @@ -518,27 +516,11 @@ func (s *Syncthing) WaitForCompletion(ctx context.Context, dev *model.Dev, repor
return nil
}

for _, folder := range s.Folders {
status, err := s.GetStatus(ctx, &folder, false)
if err != nil {
if err == errors.ErrBusySyncthing {
continue
}
return err
}
if status.PullErrors > 0 {
if err := s.GetFolderErrors(ctx, &folder, false); err != nil {
if err == errors.ErrBusySyncthing {
continue
}
}
retries++
if retries >= 60 {
return okerr.ErrUnknownSyncError
}
if err := s.GetFolderErrors(ctx, &folder, false); err != nil {
if err == errors.ErrBusySyncthing {
continue
}
retries = 0
return err
}

case <-ctx.Done():
Expand All @@ -550,27 +532,6 @@ func (s *Syncthing) WaitForCompletion(ctx context.Context, dev *model.Dev, repor
return nil
}

// GetStatus returns the syncthing status
func (s *Syncthing) GetStatus(ctx context.Context, folder *Folder, local bool) (*Status, error) {
params := getFolderParameter(folder)
status := &Status{}
body, err := s.APICall(ctx, "rest/db/status", "GET", 200, params, local, nil, true, 3)
if err != nil {
log.Infof("error getting status: %s", err.Error())
if strings.Contains(err.Error(), "Client.Timeout") {
return nil, errors.ErrBusySyncthing
}
return nil, errors.ErrLostSyncthing
}
err = json.Unmarshal(body, status)
if err != nil {
log.Infof("error unmarshalling status: %s", err.Error())
return nil, errors.ErrLostSyncthing
}

return status, nil
}

// GetCompletion returns the syncthing completion
func (s *Syncthing) GetCompletion(ctx context.Context, local bool) (*Completion, error) {
result := &Completion{}
Expand Down Expand Up @@ -622,7 +583,7 @@ func (s *Syncthing) GetFolderErrors(ctx context.Context, folder *Folder, local b
params := getFolderParameter(folder)
params["since"] = "0"
params["limit"] = "1"
params["timeout"] = "15"
params["timeout"] = "0"
params["events"] = "FolderErrors"
folderErrorsList := []FolderErrors{}
body, err := s.APICall(ctx, "rest/events", "GET", 200, params, local, nil, true, 3)
Expand Down Expand Up @@ -660,6 +621,11 @@ func (s *Syncthing) GetFolderErrors(ctx context.Context, folder *Folder, local b
return errors.ErrResetSyncthing
}

if strings.Contains(errMsg, "insufficient space") {
log.Infof("syncthing insufficient space local=%t: %s", local, errMsg)
return errors.ErrInsufficientSpace
}

log.Infof("syncthing pull error local=%t: %s", local, errMsg)
return fmt.Errorf("%s: %s", folderErrors.Data.Errors[0].Path, errMsg)
}
Expand Down

0 comments on commit 2557bc0

Please sign in to comment.