Skip to content

Commit d8e2a8d

Browse files
authored
add validation (#298)
* add validation * oops forget to restore this comment * use ImageOptions instead of a bunch of parameters * don't check error when transforming
1 parent 976cabc commit d8e2a8d

29 files changed

+519
-230
lines changed

cluster/calcium/copy.go

+9-6
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,29 @@ import (
1010

1111
// Copy uses VirtualizationCopyFrom cp to copy specified things and send to remote
1212
func (c *Calcium) Copy(ctx context.Context, opts *types.CopyOptions) (chan *types.CopyMessage, error) {
13+
if err := opts.Validate(); err != nil {
14+
return nil, err
15+
}
1316
ch := make(chan *types.CopyMessage)
1417
go func() {
1518
defer close(ch)
1619
wg := sync.WaitGroup{}
1720
log.Infof("[Copy] Copy %d workloads files", len(opts.Targets))
1821
// workload one by one
19-
for ID, paths := range opts.Targets {
22+
for id, paths := range opts.Targets {
2023
wg.Add(1)
21-
go func(ID string, paths []string) {
24+
go func(id string, paths []string) {
2225
defer wg.Done()
23-
if err := c.withWorkloadLocked(ctx, ID, func(workload *types.Workload) error {
26+
if err := c.withWorkloadLocked(ctx, id, func(workload *types.Workload) error {
2427
for _, path := range paths {
2528
resp, name, err := workload.Engine.VirtualizationCopyFrom(ctx, workload.ID, path)
26-
ch <- makeCopyMessage(ID, name, path, err, resp)
29+
ch <- makeCopyMessage(id, name, path, err, resp)
2730
}
2831
return nil
2932
}); err != nil {
30-
ch <- makeCopyMessage(ID, "", "", err, nil)
33+
ch <- makeCopyMessage(id, "", "", err, nil)
3134
}
32-
}(ID, paths)
35+
}(id, paths)
3336
}
3437
wg.Wait()
3538
}()

cluster/calcium/copy_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ import (
1616
func TestCopy(t *testing.T) {
1717
c := NewTestCluster()
1818
ctx := context.Background()
19+
20+
_, err := c.Copy(ctx, &types.CopyOptions{
21+
Targets: map[string][]string{},
22+
})
23+
assert.Error(t, err)
24+
1925
opts := &types.CopyOptions{
2026
Targets: map[string][]string{
2127
"cid": {

cluster/calcium/create.go

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ import (
2020

2121
// CreateWorkload use options to create workloads
2222
func (c *Calcium) CreateWorkload(ctx context.Context, opts *types.DeployOptions) (chan *types.CreateWorkloadMessage, error) {
23+
if err := opts.Validate(); err != nil {
24+
return nil, err
25+
}
26+
2327
opts.ProcessIdent = utils.RandomString(16)
2428
log.Infof("[CreateWorkload %s] Creating workload with options:", opts.ProcessIdent)
2529
litter.Dump(opts)

cluster/calcium/create_test.go

+32-6
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,47 @@ import (
2121
func TestCreateWorkload(t *testing.T) {
2222
c := NewTestCluster()
2323
ctx := context.Background()
24-
opts := &types.DeployOptions{}
24+
opts := &types.DeployOptions{
25+
Name: "deployname",
26+
Podname: "somepod",
27+
Image: "image:todeploy",
28+
Count: 1,
29+
Entrypoint: &types.Entrypoint{
30+
Name: "some-nice-entrypoint",
31+
},
32+
}
2533
store := c.store.(*storemocks.Store)
2634

2735
store.On("SaveProcessing", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
2836
store.On("UpdateProcessing", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
2937
store.On("DeleteProcessing", mock.Anything, mock.Anything, mock.Anything).Return(nil)
3038

31-
// failed by GetPod
32-
store.On("GetPod", mock.Anything, mock.Anything).Return(nil, types.ErrNoETCD).Once()
39+
// failed by validating
40+
opts.Name = ""
3341
_, err := c.CreateWorkload(ctx, opts)
3442
assert.Error(t, err)
35-
store.On("GetPod", mock.Anything, mock.Anything).Return(&types.Pod{Name: "test"}, nil)
36-
// failed by count
43+
opts.Name = "deployname"
44+
45+
opts.Podname = ""
46+
_, err = c.CreateWorkload(ctx, opts)
47+
assert.Error(t, err)
48+
opts.Podname = "somepod"
49+
50+
opts.Image = ""
51+
_, err = c.CreateWorkload(ctx, opts)
52+
assert.Error(t, err)
53+
opts.Image = "image:todeploy"
54+
3755
opts.Count = 0
3856
_, err = c.CreateWorkload(ctx, opts)
3957
assert.Error(t, err)
4058
opts.Count = 1
4159

60+
opts.Entrypoint.Name = "bad_entry_name"
61+
_, err = c.CreateWorkload(ctx, opts)
62+
assert.Error(t, err)
63+
opts.Entrypoint.Name = "some-nice-entrypoint"
64+
4265
// failed by memory check
4366
opts.ResourceOpts = types.ResourceOptions{MemoryLimit: -1}
4467
store.On("GetNodesByPod", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil)
@@ -61,12 +84,15 @@ func TestCreateWorkloadTxn(t *testing.T) {
6184
c := NewTestCluster()
6285
ctx := context.Background()
6386
opts := &types.DeployOptions{
87+
Name: "zc:name",
6488
Count: 2,
6589
DeployStrategy: strategy.Auto,
6690
Podname: "p1",
6791
ResourceOpts: types.ResourceOptions{CPUQuotaLimit: 1},
6892
Image: "zc:test",
69-
Entrypoint: &types.Entrypoint{},
93+
Entrypoint: &types.Entrypoint{
94+
Name: "good-entrypoint",
95+
},
7096
}
7197
store := &storemocks.Store{}
7298
sche := &schedulermocks.Scheduler{}

cluster/calcium/execute_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,20 @@ func TestExecuteWorkload(t *testing.T) {
2929
c.store = store
3030
// failed by GetWorkload
3131
store.On("GetWorkload", mock.Anything, mock.Anything).Return(nil, types.ErrBadCount).Once()
32-
ch := c.ExecuteWorkload(ctx, &types.ExecuteWorkloadOptions{}, nil)
32+
ID := "abc"
33+
ch := c.ExecuteWorkload(ctx, &types.ExecuteWorkloadOptions{WorkloadID: ID}, nil)
3334
for ac := range ch {
3435
assert.NotEmpty(t, ac.Data)
3536
}
3637
engine := &enginemocks.API{}
37-
ID := "abc"
3838
workload := &types.Workload{
3939
ID: ID,
4040
Engine: engine,
4141
}
4242
store.On("GetWorkload", mock.Anything, mock.Anything).Return(workload, nil)
4343
// failed by Execute
4444
engine.On("Execute", mock.Anything, mock.Anything, mock.Anything).Return(ID, nil, nil, types.ErrCannotGetEngine).Once()
45-
ch = c.ExecuteWorkload(ctx, &types.ExecuteWorkloadOptions{}, nil)
45+
ch = c.ExecuteWorkload(ctx, &types.ExecuteWorkloadOptions{WorkloadID: ID}, nil)
4646
for ac := range ch {
4747
assert.Equal(t, ac.WorkloadID, ID)
4848
}

cluster/calcium/image.go

+23-19
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,23 @@ import (
1010
)
1111

1212
// RemoveImage remove images
13-
func (c *Calcium) RemoveImage(ctx context.Context, podname string, nodenames []string, images []string, step int, prune bool) (chan *types.RemoveImageMessage, error) {
14-
ch := make(chan *types.RemoveImageMessage)
15-
if step < 1 {
16-
step = 1
13+
func (c *Calcium) RemoveImage(ctx context.Context, opts *types.ImageOptions) (chan *types.RemoveImageMessage, error) {
14+
if err := opts.Validate(); err != nil {
15+
return nil, err
1716
}
17+
opts.Normalize()
1818

19-
nodes, err := c.getNodes(ctx, podname, nodenames, nil, false)
19+
nodes, err := c.getNodes(ctx, opts.Podname, opts.Nodenames, nil, false)
2020
if err != nil {
21-
return ch, err
21+
return nil, err
2222
}
2323

2424
if len(nodes) == 0 {
2525
return nil, types.ErrPodNoNodes
2626
}
2727

28+
ch := make(chan *types.RemoveImageMessage)
29+
2830
go func() {
2931
defer close(ch)
3032
wg := sync.WaitGroup{}
@@ -33,7 +35,7 @@ func (c *Calcium) RemoveImage(ctx context.Context, podname string, nodenames []s
3335
wg.Add(1)
3436
go func(node *types.Node) {
3537
defer wg.Done()
36-
for _, image := range images {
38+
for _, image := range opts.Images {
3739
m := &types.RemoveImageMessage{
3840
Success: false,
3941
Image: image,
@@ -49,15 +51,15 @@ func (c *Calcium) RemoveImage(ctx context.Context, podname string, nodenames []s
4951
}
5052
ch <- m
5153
}
52-
if prune {
54+
if opts.Prune {
5355
if err := node.Engine.ImagesPrune(ctx); err != nil {
54-
log.Errorf("[RemoveImage] Prune %s pod %s node failed: %v", podname, node.Name, err)
56+
log.Errorf("[RemoveImage] Prune %s pod %s node failed: %v", opts.Podname, node.Name, err)
5557
} else {
56-
log.Infof("[RemoveImage] Prune %s pod %s node", podname, node.Name)
58+
log.Infof("[RemoveImage] Prune %s pod %s node", opts.Podname, node.Name)
5759
}
5860
}
5961
}(node)
60-
if (i+1)%step == 0 {
62+
if (i+1)%opts.Step == 0 {
6163
log.Info("[RemoveImage] Wait for previous cleaner done")
6264
wg.Wait()
6365
}
@@ -70,21 +72,23 @@ func (c *Calcium) RemoveImage(ctx context.Context, podname string, nodenames []s
7072
// CacheImage cache Image
7173
// 在podname上cache这个image
7274
// 实际上就是在所有的node上去pull一次
73-
func (c *Calcium) CacheImage(ctx context.Context, podname string, nodenames []string, images []string, step int) (chan *types.CacheImageMessage, error) {
74-
ch := make(chan *types.CacheImageMessage)
75-
if step < 1 {
76-
step = 1
75+
func (c *Calcium) CacheImage(ctx context.Context, opts *types.ImageOptions) (chan *types.CacheImageMessage, error) {
76+
if err := opts.Validate(); err != nil {
77+
return nil, err
7778
}
79+
opts.Normalize()
7880

79-
nodes, err := c.getNodes(ctx, podname, nodenames, nil, false)
81+
nodes, err := c.getNodes(ctx, opts.Podname, opts.Nodenames, nil, false)
8082
if err != nil {
81-
return ch, err
83+
return nil, err
8284
}
8385

8486
if len(nodes) == 0 {
8587
return nil, types.ErrPodNoNodes
8688
}
8789

90+
ch := make(chan *types.CacheImageMessage)
91+
8892
go func() {
8993
defer close(ch)
9094
wg := sync.WaitGroup{}
@@ -93,7 +97,7 @@ func (c *Calcium) CacheImage(ctx context.Context, podname string, nodenames []st
9397
wg.Add(1)
9498
go func(node *types.Node) {
9599
defer wg.Done()
96-
for _, image := range images {
100+
for _, image := range opts.Images {
97101
m := &types.CacheImageMessage{
98102
Image: image,
99103
Success: true,
@@ -107,7 +111,7 @@ func (c *Calcium) CacheImage(ctx context.Context, podname string, nodenames []st
107111
ch <- m
108112
}
109113
}(node)
110-
if (i+1)%step == 0 {
114+
if (i+1)%opts.Step == 0 {
111115
log.Info("[CacheImage] Wait for puller cleaner done")
112116
wg.Wait()
113117
}

cluster/calcium/image_test.go

+15-9
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ func TestRemoveImage(t *testing.T) {
1818
ctx := context.Background()
1919
store := &storemocks.Store{}
2020
c.store = store
21+
// fail by validating
22+
_, err := c.RemoveImage(ctx, &types.ImageOptions{Podname: ""})
23+
assert.Error(t, err)
2124
// fail by get nodes
2225
store.On("GetNodesByPod", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, types.ErrBadCount).Once()
23-
_, err := c.RemoveImage(ctx, "", nil, []string{}, 0, false)
26+
_, err = c.RemoveImage(ctx, &types.ImageOptions{Podname: "podname"})
2427
assert.Error(t, err)
2528
store.On("GetNodesByPod", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]*types.Node{}, nil).Once()
2629
// fail 0 nodes
27-
_, err = c.RemoveImage(ctx, "", nil, []string{}, 0, false)
30+
_, err = c.RemoveImage(ctx, &types.ImageOptions{Podname: "podname"})
2831
assert.Error(t, err)
2932
engine := &enginemocks.API{}
3033
nodes := []*types.Node{
@@ -38,19 +41,19 @@ func TestRemoveImage(t *testing.T) {
3841
store.On("GetNodesByPod", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nodes, nil)
3942
// fail remove
4043
engine.On("ImageRemove", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, types.ErrBadCount).Once()
41-
ch, err := c.RemoveImage(ctx, "", nil, []string{"xx"}, 0, false)
44+
ch, err := c.RemoveImage(ctx, &types.ImageOptions{Podname: "podname", Images: []string{"xx"}})
4245
for c := range ch {
4346
assert.False(t, c.Success)
4447
}
4548
engine.On("ImageRemove", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]string{"xx"}, nil)
4649
// sucess remove but prune fail
4750
engine.On("ImagesPrune", mock.Anything).Return(types.ErrBadStorage).Once()
48-
ch, err = c.RemoveImage(ctx, "", nil, []string{"xx"}, 0, true)
51+
ch, err = c.RemoveImage(ctx, &types.ImageOptions{Podname: "podname", Images: []string{"xx"}})
4952
for c := range ch {
5053
assert.True(t, c.Success)
5154
}
5255
engine.On("ImagesPrune", mock.Anything).Return(nil)
53-
ch, err = c.RemoveImage(ctx, "", nil, []string{"xx"}, 0, true)
56+
ch, err = c.RemoveImage(ctx, &types.ImageOptions{Podname: "podname", Images: []string{"xx"}})
5457
for c := range ch {
5558
assert.True(t, c.Success)
5659
}
@@ -61,13 +64,16 @@ func TestCacheImage(t *testing.T) {
6164
ctx := context.Background()
6265
store := &storemocks.Store{}
6366
c.store = store
67+
// fail by validating
68+
_, err := c.CacheImage(ctx, &types.ImageOptions{Podname: ""})
69+
assert.Error(t, err)
6470
// fail by get nodes
6571
store.On("GetNodesByPod", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, types.ErrBadCount).Once()
66-
_, err := c.CacheImage(ctx, "", nil, []string{}, 0)
72+
_, err = c.CacheImage(ctx, &types.ImageOptions{Podname: "podname"})
6773
assert.Error(t, err)
6874
store.On("GetNodesByPod", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]*types.Node{}, nil).Once()
6975
// fail 0 nodes
70-
_, err = c.CacheImage(ctx, "", nil, []string{}, 0)
76+
_, err = c.CacheImage(ctx, &types.ImageOptions{Podname: "podname"})
7177
assert.Error(t, err)
7278
engine := &enginemocks.API{}
7379
nodes := []*types.Node{
@@ -83,15 +89,15 @@ func TestCacheImage(t *testing.T) {
8389
engine.On("ImageRemoteDigest", mock.Anything, mock.Anything).Return("", types.ErrNoETCD).Once()
8490
engine.On("ImageLocalDigests", mock.Anything, mock.Anything).Return(nil, types.ErrNoETCD).Once()
8591
engine.On("ImagePull", mock.Anything, mock.Anything, mock.Anything).Return(nil, types.ErrNoETCD).Once()
86-
ch, err := c.CacheImage(ctx, "", nil, []string{"xx"}, 0)
92+
ch, err := c.CacheImage(ctx, &types.ImageOptions{Podname: "podname", Images: []string{"xx"}})
8793
for c := range ch {
8894
assert.False(t, c.Success)
8995
}
9096
engine.On("ImageRemoteDigest", mock.Anything, mock.Anything).Return("yy", nil)
9197
engine.On("ImageLocalDigests", mock.Anything, mock.Anything).Return([]string{"xx"}, nil)
9298
engine.On("ImagePull", mock.Anything, mock.Anything, mock.Anything).Return(ioutil.NopCloser(bytes.NewReader([]byte{})), nil)
9399
// succ
94-
ch, err = c.CacheImage(ctx, "", nil, []string{"xx"}, 0)
100+
ch, err = c.CacheImage(ctx, &types.ImageOptions{Podname: "podname", Images: []string{"xx"}})
95101
for c := range ch {
96102
assert.True(t, c.Success)
97103
}

cluster/calcium/lambda.go

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ const exitDataPrefix = "[exitcode] "
1717

1818
// RunAndWait implement lambda
1919
func (c *Calcium) RunAndWait(ctx context.Context, opts *types.DeployOptions, inCh <-chan []byte) (<-chan *types.AttachWorkloadMessage, error) {
20+
if err := opts.Validate(); err != nil {
21+
return nil, err
22+
}
2023
opts.Lambda = true
2124
// count = 1 && OpenStdin
2225
if opts.OpenStdin && (opts.Count != 1 || opts.DeployStrategy != strategy.Auto) {

cluster/calcium/lock.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func (c *Calcium) withWorkloadsLocked(ctx context.Context, IDs []string, f func(
7474
func (c *Calcium) withNodesLocked(ctx context.Context, podname string, nodenames []string, labels map[string]string, all bool, f func(nodes map[string]*types.Node) error) error {
7575
nodes := map[string]*types.Node{}
7676
locks := map[string]lock.DistributedLock{}
77-
defer func() { c.doUnlockAll(ctx, locks) }()
77+
defer c.doUnlockAll(ctx, locks)
7878
ns, err := c.getNodes(ctx, podname, nodenames, labels, all)
7979
if err != nil {
8080
return err

cluster/calcium/node.go

+12
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,18 @@ import (
1010

1111
// AddNode adds a node
1212
func (c *Calcium) AddNode(ctx context.Context, opts *types.AddNodeOptions) (*types.Node, error) {
13+
if err := opts.Validate(); err != nil {
14+
return nil, err
15+
}
1316
opts.Normalize()
1417
return c.store.AddNode(ctx, opts)
1518
}
1619

1720
// RemoveNode remove a node
1821
func (c *Calcium) RemoveNode(ctx context.Context, nodename string) error {
22+
if nodename == "" {
23+
return types.ErrEmptyNodeName
24+
}
1925
return c.withNodeLocked(ctx, nodename, func(node *types.Node) error {
2026
ws, err := c.ListNodeWorkloads(ctx, node.Name, nil)
2127
if err != nil {
@@ -35,11 +41,17 @@ func (c *Calcium) ListPodNodes(ctx context.Context, podname string, labels map[s
3541

3642
// GetNode get node
3743
func (c *Calcium) GetNode(ctx context.Context, nodename string) (*types.Node, error) {
44+
if nodename == "" {
45+
return nil, types.ErrEmptyNodeName
46+
}
3847
return c.store.GetNode(ctx, nodename)
3948
}
4049

4150
// SetNode set node available or not
4251
func (c *Calcium) SetNode(ctx context.Context, opts *types.SetNodeOptions) (*types.Node, error) { // nolint
52+
if err := opts.Validate(); err != nil {
53+
return nil, err
54+
}
4355
var n *types.Node
4456
return n, c.withNodeLocked(ctx, opts.Nodename, func(node *types.Node) error {
4557
litter.Dump(opts)

0 commit comments

Comments
 (0)