github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/common/remove.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common 5 6 import ( 7 "fmt" 8 "time" 9 10 "github.com/juju/errors" 11 "github.com/juju/names/v5" 12 13 apiservererrors "github.com/juju/juju/apiserver/errors" 14 "github.com/juju/juju/rpc/params" 15 "github.com/juju/juju/state" 16 ) 17 18 // Remover implements a common Remove method for use by various facades. 19 type Remover struct { 20 st state.EntityFinder 21 afterDead func(tag names.Tag) 22 callEnsureDead bool 23 getCanModify GetAuthFunc 24 } 25 26 // NewRemover returns a new Remover. The callEnsureDead flag specifies 27 // whether EnsureDead should be called on an entity before 28 // removing. The GetAuthFunc will be used on each invocation of Remove 29 // to determine current permissions. 30 func NewRemover(st state.EntityFinder, afterDead func(tag names.Tag), callEnsureDead bool, getCanModify GetAuthFunc) *Remover { 31 return &Remover{ 32 st: st, 33 afterDead: afterDead, 34 callEnsureDead: callEnsureDead, 35 getCanModify: getCanModify, 36 } 37 } 38 39 func (r *Remover) removeEntity(tag names.Tag) error { 40 entity, err := r.st.FindEntity(tag) 41 if err != nil { 42 return err 43 } 44 remover, ok := entity.(interface { 45 state.Lifer 46 state.Remover 47 state.EnsureDeader 48 }) 49 if !ok { 50 return apiservererrors.NotSupportedError(tag, "removal") 51 } 52 // Only remove entities that are not Alive. 53 if life := remover.Life(); life == state.Alive { 54 return fmt.Errorf("cannot remove entity %q: still alive", tag.String()) 55 } 56 if r.callEnsureDead { 57 if err := remover.EnsureDead(); err != nil { 58 return err 59 } 60 if r.afterDead != nil { 61 r.afterDead(tag) 62 } 63 } 64 // TODO (anastasiamac) this needs to work with force if needed 65 return remover.Remove() 66 } 67 68 // Remove removes every given entity from state, calling EnsureDead 69 // first, then Remove. It will fail if the entity is not present. 70 func (r *Remover) Remove(args params.Entities) (params.ErrorResults, error) { 71 result := params.ErrorResults{ 72 Results: make([]params.ErrorResult, len(args.Entities)), 73 } 74 if len(args.Entities) == 0 { 75 return result, nil 76 } 77 canModify, err := r.getCanModify() 78 if err != nil { 79 return params.ErrorResults{}, errors.Trace(err) 80 } 81 for i, entity := range args.Entities { 82 tag, err := names.ParseTag(entity.Tag) 83 if err != nil { 84 result.Results[i].Error = apiservererrors.ServerError(apiservererrors.ErrPerm) 85 continue 86 } 87 err = apiservererrors.ErrPerm 88 if canModify(tag) { 89 err = r.removeEntity(tag) 90 } 91 result.Results[i].Error = apiservererrors.ServerError(err) 92 } 93 return result, nil 94 } 95 96 // MaxWait is how far in the future the backstop force cleanup will be scheduled. 97 // Default is 1min if no value is provided. 98 func MaxWait(in *time.Duration) time.Duration { 99 if in != nil { 100 return *in 101 } 102 return 1 * time.Minute 103 }