github.com/percona/percona-xtradb-cluster-operator@v1.14.0/pkg/k8s/graceful_shutdown.go (about) 1 package k8s 2 3 import ( 4 "context" 5 "time" 6 7 api "github.com/percona/percona-xtradb-cluster-operator/pkg/apis/pxc/v1" 8 "github.com/pkg/errors" 9 k8serrors "k8s.io/apimachinery/pkg/api/errors" 10 "sigs.k8s.io/controller-runtime/pkg/client" 11 logf "sigs.k8s.io/controller-runtime/pkg/log" 12 "sigs.k8s.io/controller-runtime/pkg/manager/signals" 13 ) 14 15 var log = logf.Log 16 17 // StartStopSignalHandler starts gorutine which is waiting for termination 18 // signal and returns a context which is cancelled when operator can really 19 // stop. 20 func StartStopSignalHandler(client client.Client, namespaces []string) context.Context { 21 ctx, shutdownFunc := context.WithCancel(context.Background()) 22 go handleStopSignal(client, namespaces, shutdownFunc) 23 return ctx 24 } 25 26 func handleStopSignal(client client.Client, namespaces []string, shutdownFunc context.CancelFunc) { 27 <-signals.SetupSignalHandler().Done() 28 stop(client, namespaces) 29 shutdownFunc() 30 } 31 32 // Stop is used to understand, when we need to stop operator(usially SIGTERM) 33 // to start cleanup process and delete required pxc clusters in current(operator) 34 // namespace. See K8SPXC-529 35 func stop(cl client.Client, namespaces []string) { 36 log.Info("Got stop signal, starting to list clusters") 37 38 readyToDelete := false 39 40 for !readyToDelete { 41 time.Sleep(5 * time.Second) 42 ready, err := checkClusters(cl, namespaces) 43 if err != nil { 44 log.Error(err, "delete clusters") 45 } 46 readyToDelete = ready 47 } 48 } 49 50 func checkClusters(cl client.Client, namespaces []string) (bool, error) { 51 for _, ns := range namespaces { 52 53 clusterList := &api.PerconaXtraDBClusterList{} 54 55 err := cl.List(context.TODO(), clusterList, &client.ListOptions{Namespace: ns}) 56 if err != nil && !k8serrors.IsNotFound(err) { 57 return false, errors.Wrapf(err, "list clusters in namespace: %s", ns) 58 } 59 60 if clusterList.HasUnfinishedFinalizers() { 61 return false, nil 62 } 63 64 bcpList := api.PerconaXtraDBClusterBackupList{} 65 66 err = cl.List(context.TODO(), &bcpList, &client.ListOptions{Namespace: ns}) 67 if err != nil && !k8serrors.IsNotFound(err) { 68 return false, errors.Wrap(err, "failed to get backup object") 69 } 70 71 if bcpList.HasUnfinishedFinalizers() { 72 return false, nil 73 } 74 } 75 76 return true, nil 77 }