github.com/projecteru2/core@v0.0.0-20240321043226-06bcc1c23f58/cluster/calcium/control.go (about)

     1  package calcium
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"sync"
     7  
     8  	"github.com/projecteru2/core/cluster"
     9  	"github.com/projecteru2/core/log"
    10  	"github.com/projecteru2/core/types"
    11  	"github.com/projecteru2/core/utils"
    12  )
    13  
    14  // ControlWorkload control workloads status
    15  func (c *Calcium) ControlWorkload(ctx context.Context, IDs []string, typ string, force bool) (chan *types.ControlWorkloadMessage, error) {
    16  	logger := log.WithFunc("calcium.ControlWorkload").WithField("IDs", IDs).WithField("typ", typ).WithField("force", force)
    17  	ch := make(chan *types.ControlWorkloadMessage)
    18  
    19  	_ = c.pool.Invoke(func() {
    20  		defer close(ch)
    21  		wg := &sync.WaitGroup{}
    22  		wg.Add(len(IDs))
    23  		defer wg.Wait()
    24  		for _, ID := range IDs {
    25  			ID := ID
    26  			_ = c.pool.Invoke(func() {
    27  				defer wg.Done()
    28  				var message []*bytes.Buffer
    29  				err := c.withWorkloadLocked(ctx, ID, false, func(ctx context.Context, workload *types.Workload) error {
    30  					var err error
    31  					switch typ {
    32  					case cluster.WorkloadStop:
    33  						message, err = c.doStopWorkload(ctx, workload, force)
    34  						return err
    35  					case cluster.WorkloadStart:
    36  						message, err = c.doStartWorkload(ctx, workload, force)
    37  						return err
    38  					case cluster.WorkloadRestart:
    39  						message, err = c.doStopWorkload(ctx, workload, force)
    40  						if err != nil {
    41  							return err
    42  						}
    43  						startHook, err := c.doStartWorkload(ctx, workload, force)
    44  						message = append(message, startHook...)
    45  						return err
    46  					case cluster.WorkloadSuspend:
    47  						message, err = c.doSuspendWorkload(ctx, workload, force)
    48  						return err
    49  					case cluster.WorkloadResume:
    50  						message, err = c.doResumeWorkload(ctx, workload, force)
    51  						return err
    52  					}
    53  					return types.ErrInvaildControlType
    54  				})
    55  				if err == nil {
    56  					logger.Infof(ctx, "Workload %s %s", ID, typ)
    57  					logger.Infof(ctx, "%+v", "Hook Output:")
    58  					logger.Infof(ctx, "%+v", string(utils.MergeHookOutputs(message)))
    59  				}
    60  				logger.Error(ctx, err)
    61  				ch <- &types.ControlWorkloadMessage{
    62  					WorkloadID: ID,
    63  					Error:      err,
    64  					Hook:       message,
    65  				}
    66  			})
    67  		}
    68  	})
    69  
    70  	return ch, nil
    71  }
    72  
    73  func (c *Calcium) doStartWorkload(ctx context.Context, workload *types.Workload, force bool) (message []*bytes.Buffer, err error) {
    74  	if err = workload.Start(ctx); err != nil {
    75  		return message, err
    76  	}
    77  	// TODO healthcheck first
    78  	if workload.Hook != nil && len(workload.Hook.AfterStart) > 0 {
    79  		message, err = c.doHook(
    80  			ctx,
    81  			workload.ID, workload.User,
    82  			workload.Hook.AfterStart, workload.Env,
    83  			workload.Hook.Force, workload.Privileged,
    84  			force, workload.Engine,
    85  		)
    86  	}
    87  	return message, err
    88  }
    89  
    90  func (c *Calcium) doStopWorkload(ctx context.Context, workload *types.Workload, force bool) (message []*bytes.Buffer, err error) {
    91  	if workload.Hook != nil && len(workload.Hook.BeforeStop) > 0 {
    92  		message, err = c.doHook(
    93  			ctx,
    94  			workload.ID, workload.User,
    95  			workload.Hook.BeforeStop, workload.Env,
    96  			workload.Hook.Force, workload.Privileged,
    97  			force, workload.Engine,
    98  		)
    99  		if err != nil {
   100  			return message, err
   101  		}
   102  	}
   103  
   104  	// 这里 block 的问题很严重,按照目前的配置是 5 分钟一级的 block
   105  	// 一个简单的处理方法是相信 ctx 不相信 engine 自身的处理
   106  	// 另外我怀疑 engine 自己的 timeout 实现是完全的等 timeout 而非结束了就退出
   107  	if err = workload.Stop(ctx, force); err != nil {
   108  		message = append(message, bytes.NewBufferString(err.Error()))
   109  	}
   110  	return message, err
   111  }
   112  
   113  func (c *Calcium) doSuspendWorkload(ctx context.Context, workload *types.Workload, force bool) (message []*bytes.Buffer, err error) {
   114  	if workload.Hook != nil && len(workload.Hook.BeforeSuspend) > 0 {
   115  		message, err = c.doHook(
   116  			ctx,
   117  			workload.ID, workload.User,
   118  			workload.Hook.BeforeSuspend, workload.Env,
   119  			workload.Hook.Force, workload.Privileged,
   120  			force, workload.Engine,
   121  		)
   122  		if err != nil {
   123  			return message, err
   124  		}
   125  	}
   126  
   127  	if err = workload.Suspend(ctx); err != nil {
   128  		message = append(message, bytes.NewBufferString(err.Error()))
   129  	}
   130  	return message, err
   131  }
   132  
   133  func (c *Calcium) doResumeWorkload(ctx context.Context, workload *types.Workload, force bool) (message []*bytes.Buffer, err error) {
   134  	if err = workload.Resume(ctx); err != nil {
   135  		return message, err
   136  	}
   137  	if workload.Hook != nil && len(workload.Hook.AfterResume) > 0 {
   138  		message, err = c.doHook(
   139  			ctx,
   140  			workload.ID, workload.User,
   141  			workload.Hook.AfterResume, workload.Env,
   142  			workload.Hook.Force, workload.Privileged,
   143  			force, workload.Engine,
   144  		)
   145  	}
   146  	return message, err
   147  }