TUN-3599: improved delete if credentials isnt found.
Tunnel delete is successful even if we don't find the credentials file in the user's filesystem. We no longer "error" indicating this is a problem. This fix also enables chaining of the delete command by removing a pre-mature return if the credentials file is not found.
This commit is contained in:
parent
38fb0b28b6
commit
1c0dac77d7
|
@ -228,14 +228,10 @@ func (sc *subcommandContext) delete(tunnelIDs []uuid.UUID) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
credFinder := sc.credentialFinder(id)
|
credFinder := sc.credentialFinder(id)
|
||||||
tunnelCredentialsPath, err := credFinder.Path()
|
if tunnelCredentialsPath, err := credFinder.Path(); err == nil {
|
||||||
if err != nil {
|
|
||||||
sc.logger.Infof("Cannot locate tunnel credentials to delete, error: %v. Please delete the file manually", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = os.Remove(tunnelCredentialsPath); err != nil {
|
if err = os.Remove(tunnelCredentialsPath); err != nil {
|
||||||
sc.logger.Infof("Cannot delete tunnel credentials, error: %v. Please delete the file manually", err)
|
sc.logger.Infof("Tunnel %v was deleted, but we could not remove its credentials file %s: %s. Consider deleting this file manually.", id, tunnelCredentialsPath, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/cloudflare/cloudflared/connection"
|
"github.com/cloudflare/cloudflared/connection"
|
||||||
"github.com/cloudflare/cloudflared/logger"
|
"github.com/cloudflare/cloudflared/logger"
|
||||||
|
@ -213,3 +214,141 @@ func Test_subcommandContext_findCredentials(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type deleteMockTunnelStore struct {
|
||||||
|
tunnelstore.Client
|
||||||
|
mockTunnels map[uuid.UUID]mockTunnelBehaviour
|
||||||
|
deletedTunnelIDs []uuid.UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
type mockTunnelBehaviour struct {
|
||||||
|
tunnel tunnelstore.Tunnel
|
||||||
|
deleteErr error
|
||||||
|
cleanupErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDeleteMockTunnelStore(tunnels ...mockTunnelBehaviour) *deleteMockTunnelStore {
|
||||||
|
mockTunnels := make(map[uuid.UUID]mockTunnelBehaviour)
|
||||||
|
for _, tunnel := range tunnels {
|
||||||
|
mockTunnels[tunnel.tunnel.ID] = tunnel
|
||||||
|
}
|
||||||
|
return &deleteMockTunnelStore{
|
||||||
|
mockTunnels: mockTunnels,
|
||||||
|
deletedTunnelIDs: make([]uuid.UUID, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deleteMockTunnelStore) GetTunnel(tunnelID uuid.UUID) (*tunnelstore.Tunnel, error) {
|
||||||
|
tunnel, ok := d.mockTunnels[tunnelID]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("Couldn't find tunnel: %v", tunnelID)
|
||||||
|
}
|
||||||
|
return &tunnel.tunnel, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deleteMockTunnelStore) DeleteTunnel(tunnelID uuid.UUID) error {
|
||||||
|
tunnel, ok := d.mockTunnels[tunnelID]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Couldn't find tunnel: %v", tunnelID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tunnel.deleteErr != nil {
|
||||||
|
return tunnel.deleteErr
|
||||||
|
}
|
||||||
|
|
||||||
|
d.deletedTunnelIDs = append(d.deletedTunnelIDs, tunnelID)
|
||||||
|
tunnel.tunnel.DeletedAt = time.Now()
|
||||||
|
delete(d.mockTunnels, tunnelID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deleteMockTunnelStore) CleanupConnections(tunnelID uuid.UUID) error {
|
||||||
|
tunnel, ok := d.mockTunnels[tunnelID]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Couldn't find tunnel: %v", tunnelID)
|
||||||
|
}
|
||||||
|
return tunnel.cleanupErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_subcommandContext_Delete(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
c *cli.Context
|
||||||
|
logger logger.Service
|
||||||
|
isUIEnabled bool
|
||||||
|
fs fileSystem
|
||||||
|
tunnelstoreClient *deleteMockTunnelStore
|
||||||
|
userCredential *userCredential
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
tunnelIDs []uuid.UUID
|
||||||
|
}
|
||||||
|
newCertPath := "new_cert.json"
|
||||||
|
tunnelID1 := uuid.MustParse("df5ed608-b8b4-4109-89f3-9f2cf199df64")
|
||||||
|
tunnelID2 := uuid.MustParse("af5ed608-b8b4-4109-89f3-9f2cf199df64")
|
||||||
|
logger, err := logger.New()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var tests = []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
want []uuid.UUID
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "clean up continues if credentials are not found",
|
||||||
|
fields: fields{
|
||||||
|
logger: logger,
|
||||||
|
fs: mockFileSystem{
|
||||||
|
rf: func(filePath string) ([]byte, error) {
|
||||||
|
return nil, errors.New("file not found")
|
||||||
|
},
|
||||||
|
vfp: func(string) bool { return true },
|
||||||
|
},
|
||||||
|
c: func() *cli.Context {
|
||||||
|
flagSet := flag.NewFlagSet("test0", flag.PanicOnError)
|
||||||
|
flagSet.String(CredFileFlag, newCertPath, "")
|
||||||
|
c := cli.NewContext(cli.NewApp(), flagSet, nil)
|
||||||
|
err = c.Set(CredFileFlag, newCertPath)
|
||||||
|
return c
|
||||||
|
}(),
|
||||||
|
tunnelstoreClient: newDeleteMockTunnelStore(
|
||||||
|
mockTunnelBehaviour{
|
||||||
|
tunnel: tunnelstore.Tunnel{ID: tunnelID1},
|
||||||
|
},
|
||||||
|
mockTunnelBehaviour{
|
||||||
|
tunnel: tunnelstore.Tunnel{ID: tunnelID2},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
|
args: args{
|
||||||
|
tunnelIDs: []uuid.UUID{tunnelID1, tunnelID2},
|
||||||
|
},
|
||||||
|
want: []uuid.UUID{tunnelID1, tunnelID2},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
sc := &subcommandContext{
|
||||||
|
c: tt.fields.c,
|
||||||
|
logger: tt.fields.logger,
|
||||||
|
isUIEnabled: tt.fields.isUIEnabled,
|
||||||
|
fs: tt.fields.fs,
|
||||||
|
tunnelstoreClient: tt.fields.tunnelstoreClient,
|
||||||
|
userCredential: tt.fields.userCredential,
|
||||||
|
}
|
||||||
|
err := sc.delete(tt.args.tunnelIDs)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("subcommandContext.findCredentials() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
got := tt.fields.tunnelstoreClient.deletedTunnelIDs
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("subcommandContext.findCredentials() = %v, want %v", got, tt.want)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue