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  }