diff --git a/scheduler/complex/potassium.go b/scheduler/complex/potassium.go index 98573c677..71827ac34 100644 --- a/scheduler/complex/potassium.go +++ b/scheduler/complex/potassium.go @@ -147,7 +147,7 @@ func (m *Potassium) SelectCPUNodes(ctx context.Context, scheduleInfos []resource } log.Infof(ctx, "[SelectCPUNodes] resources %v, need cpu: %f memory: %d", resources, quota, memory) if quota <= 0 { - return nil, nil, 0, errors.WithStack(types.ErrNegativeQuota) + return nil, nil, 0, errors.WithStack(types.ErrNegativeCPU) } if len(scheduleInfos) == 0 { return nil, nil, 0, errors.WithStack(types.ErrZeroNodes) diff --git a/store/etcdv3/pod.go b/store/etcdv3/pod.go index 6429eb453..a13318584 100644 --- a/store/etcdv3/pod.go +++ b/store/etcdv3/pod.go @@ -21,7 +21,13 @@ func (m *Mercury) AddPod(ctx context.Context, name, desc string) (*types.Pod, er if err != nil { return nil, err } - _, err = m.Put(ctx, key, string(bytes)) + resp, err := m.BatchCreate(ctx, map[string]string{key: string(bytes)}) + if err != nil { + return nil, err + } + if !resp.Succeeded { + return nil, types.ErrTxnConditionFailed + } return pod, err } diff --git a/store/etcdv3/pod_test.go b/store/etcdv3/pod_test.go index 2c6d1fedd..5c637cfdd 100644 --- a/store/etcdv3/pod_test.go +++ b/store/etcdv3/pod_test.go @@ -18,6 +18,9 @@ func TestPod(t *testing.T) { assert.NoError(t, err) assert.Equal(t, pod.Name, podname) + _, err = m.AddPod(ctx, podname, "CPU") + assert.Equal(t, err, types.ErrKeyExists) + pod2, err := m.GetPod(ctx, podname) assert.NoError(t, err) assert.Equal(t, pod2.Name, podname) diff --git a/store/redis/pod.go b/store/redis/pod.go index 8a697b2f9..4cde7442c 100644 --- a/store/redis/pod.go +++ b/store/redis/pod.go @@ -17,7 +17,7 @@ func (r *Rediaron) AddPod(ctx context.Context, name, desc string) (*types.Pod, e if err != nil { return nil, err } - _, err = r.cli.Set(ctx, key, string(bytes), 0).Result() + err = r.BatchCreate(ctx, map[string]string{key: string(bytes)}) return pod, err } diff --git a/store/redis/pod_test.go b/store/redis/pod_test.go index f9c5288af..260a5108e 100644 --- a/store/redis/pod_test.go +++ b/store/redis/pod_test.go @@ -14,6 +14,9 @@ func (s *RediaronTestSuite) TestPod() { s.NoError(err) s.Equal(pod.Name, podname) + _, err = s.rediaron.AddPod(ctx, podname, "CPU") + s.Equal(err, ErrAlreadyExists) + pod2, err := s.rediaron.GetPod(ctx, podname) s.NoError(err) s.Equal(pod2.Name, podname) diff --git a/types/errors.go b/types/errors.go index 80b1535c9..ac6ddb4ec 100644 --- a/types/errors.go +++ b/types/errors.go @@ -17,10 +17,6 @@ var ( ErrInsufficientNodes = errors.New("not enough nodes") ErrAlreadyFilled = errors.New("Cannot alloc a fill node plan, each node has enough workloads") - ErrNegativeMemory = errors.New("memory must be positive") - ErrNegativeStorage = errors.New("storage must be positive") - ErrNegativeQuota = errors.New("quota must be positive") - ErrZeroNodes = errors.New("no nodes provide to choose some") ErrNodeFormat = errors.New("bad endpoint name") @@ -119,13 +115,19 @@ func NewDetailedErr(err error, details interface{}) error { // validation errors var ( - ErrEmptyNodeName = errors.New("node name is empty") - ErrEmptyAppName = errors.New("app name is empty") - ErrEmptyPodName = errors.New("pod name is empty") - ErrEmptyNodeEndpoint = errors.New("node endpoint is empty") - ErrEmptyImage = errors.New("image is empty") - ErrEmptyCount = errors.New("count is 0") - ErrEmptyWorkloadID = errors.New("workload id is empty") + ErrEmptyNodeName = errors.New("node name is empty") + ErrEmptyAppName = errors.New("app name is empty") + ErrEmptyPodName = errors.New("pod name is empty") + ErrEmptyNodeEndpoint = errors.New("node endpoint is empty") + ErrEmptyImage = errors.New("image is empty") + ErrEmptyCount = errors.New("count is 0") + ErrEmptyWorkloadID = errors.New("workload id is empty") + ErrNegativeCPU = errors.New("cpu is negative") + ErrNegativeShare = errors.New("share is negative") + ErrNegativeMemory = errors.New("memory is negative") + ErrNegativeNUMAMemory = errors.New("numa memory is negative") + ErrNegativeStorage = errors.New("storage is negative") + ErrNegativeVolumeSize = errors.New("volume size is negative") ErrEmptyEntrypointName = errors.New("entrypoint name is empty") ErrUnderlineInEntrypointName = errors.New("entrypoint name has '_' character") diff --git a/types/options.go b/types/options.go index 83d772c04..a7eb60cb0 100644 --- a/types/options.go +++ b/types/options.go @@ -204,6 +204,28 @@ func (o *AddNodeOptions) Validate() error { if o.Endpoint == "" { return errors.WithStack(ErrEmptyNodeEndpoint) } + if o.CPU < 0 { + return errors.WithStack(ErrNegativeCPU) + } + if o.Share < 0 { + return errors.WithStack(ErrNegativeShare) + } + if o.Memory < 0 { + return errors.WithStack(ErrNegativeMemory) + } + for _, m := range o.NumaMemory { + if m < 0 { + return errors.WithStack(ErrNegativeNUMAMemory) + } + } + for _, size := range o.Volume { + if size < 0 { + return errors.WithStack(ErrNegativeVolumeSize) + } + } + if o.Storage < 0 { + return errors.WithStack(ErrNegativeStorage) + } return nil } diff --git a/types/options_test.go b/types/options_test.go index b3fe695d4..727f6f304 100644 --- a/types/options_test.go +++ b/types/options_test.go @@ -138,6 +138,25 @@ func TestValidatingAddNodeOptions(t *testing.T) { assert.Equal(ErrEmptyNodeEndpoint, errors.Unwrap(o.Validate())) o.Endpoint = "tcp://endpoint:2376" + o.CPU = -1 + o.Share = -1 + o.Memory = -1 + o.NumaMemory = NUMAMemory{"0": -1} + o.Volume = VolumeMap{"/data": -1} + o.Storage = -1 + + assert.Equal(ErrNegativeCPU, errors.Unwrap(o.Validate())) + o.CPU = 1 + assert.Equal(ErrNegativeShare, errors.Unwrap(o.Validate())) + o.Share = 100 + assert.Equal(ErrNegativeMemory, errors.Unwrap(o.Validate())) + o.Memory = 100 + assert.Equal(ErrNegativeNUMAMemory, errors.Unwrap(o.Validate())) + o.NumaMemory = nil + assert.Equal(ErrNegativeVolumeSize, errors.Unwrap(o.Validate())) + o.Volume = nil + assert.Equal(ErrNegativeStorage, errors.Unwrap(o.Validate())) + o.Storage = 1 assert.NoError(o.Validate()) }