Skip to content

Commit 07af45c

Browse files
committed
Merge branch 'master' into deployment-phase
2 parents 45087c7 + 53c7c74 commit 07af45c

23 files changed

+618
-81
lines changed

Jenkinsfile.groovy

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ def fetchParamsFromGitLog() {
2626
myParams[entry.key] = entry.value;
2727
}
2828

29+
// Is this a LONG test?
30+
if ("${env.JOB_NAME}" == "kube-arangodb-long") {
31+
myParams["LONG"] = true;
32+
}
33+
2934
// Fetch params configured in git commit messages
3035
// Syntax: [ci OPT=value]
3136
// Example: [ci TESTOPTIONS="-test.run ^TestSimpleSingle$"]

Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ endif
5050
endif
5151
MANIFESTPATHDEPLOYMENT := manifests/arango-deployment$(MANIFESTSUFFIX).yaml
5252
MANIFESTPATHSTORAGE := manifests/arango-storage$(MANIFESTSUFFIX).yaml
53+
MANIFESTPATHTEST := manifests/arango-test$(MANIFESTSUFFIX).yaml
5354
ifndef DEPLOYMENTNAMESPACE
5455
DEPLOYMENTNAMESPACE := default
5556
endif
@@ -75,7 +76,7 @@ TESTLENGTHOPTIONS := -test.short
7576
TESTTIMEOUT := 20m
7677
ifeq ($(LONG), 1)
7778
TESTLENGTHOPTIONS :=
78-
TESTTIMEOUT := 40m
79+
TESTTIMEOUT := 60m
7980
endif
8081
ifdef VERBOSE
8182
TESTVERBOSEOPTIONS := -v
@@ -216,6 +217,7 @@ run-unit-tests: $(GOBUILDDIR) $(SOURCES)
216217
golang:$(GOVERSION) \
217218
go test $(TESTVERBOSEOPTIONS) \
218219
$(REPOPATH)/pkg/apis/deployment/v1alpha \
220+
$(REPOPATH)/pkg/apis/storage/v1alpha \
219221
$(REPOPATH)/pkg/deployment/reconcile \
220222
$(REPOPATH)/pkg/deployment/resources \
221223
$(REPOPATH)/pkg/util/k8sutil \
@@ -251,6 +253,7 @@ endif
251253
kubectl apply -f manifests/crd.yaml
252254
kubectl apply -f $(MANIFESTPATHSTORAGE)
253255
kubectl apply -f $(MANIFESTPATHDEPLOYMENT)
256+
kubectl apply -f $(MANIFESTPATHTEST)
254257
$(ROOTDIR)/scripts/kube_create_storage.sh $(DEPLOYMENTNAMESPACE)
255258
$(ROOTDIR)/scripts/kube_run_tests.sh $(DEPLOYMENTNAMESPACE) $(TESTIMAGE) "$(ENTERPRISEIMAGE)" $(TESTTIMEOUT) $(TESTLENGTHOPTIONS)
256259
ifneq ($(DEPLOYMENTNAMESPACE), default)
@@ -312,6 +315,7 @@ minikube-start:
312315

313316
.PHONY: delete-operator
314317
delete-operator:
318+
kubectl delete -f $(MANIFESTPATHTEST) --ignore-not-found
315319
kubectl delete -f $(MANIFESTPATHDEPLOYMENT) --ignore-not-found
316320
kubectl delete -f $(MANIFESTPATHSTORAGE) --ignore-not-found
317321

@@ -320,4 +324,5 @@ redeploy-operator: delete-operator manifests
320324
kubectl apply -f manifests/crd.yaml
321325
kubectl apply -f $(MANIFESTPATHSTORAGE)
322326
kubectl apply -f $(MANIFESTPATHDEPLOYMENT)
327+
kubectl apply -f $(MANIFESTPATHTEST)
323328
kubectl get pods

manifests/.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
arango-deployment-dev.yaml
2-
arango-storage-dev.yaml
2+
arango-storage-dev.yaml
3+
arango-test-dev.yaml

manifests/templates/deployment/rbac.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,4 @@ subjects:
6969
name: {{ .Deployment.Operator.ServiceAccountName }}
7070
namespace: {{ .Deployment.Operator.Namespace }}
7171

72-
{{- end -}}
72+
{{- end -}}

manifests/templates/test/rbac.yaml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{{- if .RBAC -}}
2+
3+
## Cluster role granting access to resources needed by the integration tests.
4+
apiVersion: rbac.authorization.k8s.io/v1beta1
5+
kind: ClusterRole
6+
metadata:
7+
name: {{ .Test.RoleName }}
8+
rules:
9+
- apiGroups: [""]
10+
resources: ["nodes"]
11+
verbs: ["list"]
12+
13+
---
14+
15+
## Bind the cluster role granting access to ArangoLocalStorage resources
16+
## to the default service account of the configured namespace.
17+
apiVersion: rbac.authorization.k8s.io/v1beta1
18+
kind: ClusterRoleBinding
19+
metadata:
20+
name: {{ .Test.RoleBindingName }}
21+
namespace: {{ .Test.Namespace }}
22+
roleRef:
23+
apiGroup: rbac.authorization.k8s.io
24+
kind: ClusterRole
25+
name: {{ .Test.RoleName }}
26+
subjects:
27+
- kind: ServiceAccount
28+
name: {{ .Test.ServiceAccountName }}
29+
namespace: {{ .Test.Namespace }}
30+
31+
{{- end -}}

pkg/apis/deployment/v1alpha/member_status.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@
2222

2323
package v1alpha
2424

25+
import (
26+
"time"
27+
28+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29+
)
30+
2531
// MemberStatus holds the current status of a single member (server)
2632
type MemberStatus struct {
2733
// ID holds the unique ID of the member.
@@ -35,4 +41,40 @@ type MemberStatus struct {
3541
PodName string `json:"podName,omitempty"`
3642
// Conditions specific to this member
3743
Conditions ConditionList `json:"conditions,omitempty"`
44+
// RecentTerminatons holds the times when this member was recently terminated.
45+
// First entry is the oldest. (do not add omitempty, since we want to be able to switch from a list to an empty list)
46+
RecentTerminations []metav1.Time `json:"recent-terminations"`
47+
}
48+
49+
// RemoveTerminationsBefore removes all recent terminations before the given timestamp.
50+
// It returns the number of terminations that have been removed.
51+
func (s *MemberStatus) RemoveTerminationsBefore(timestamp time.Time) int {
52+
removed := 0
53+
for {
54+
if len(s.RecentTerminations) == 0 {
55+
// Nothing left
56+
return removed
57+
}
58+
if s.RecentTerminations[0].Time.Before(timestamp) {
59+
// Let's remove it
60+
s.RecentTerminations = s.RecentTerminations[1:]
61+
removed++
62+
} else {
63+
// First (oldest) is not before given timestamp, we're done
64+
return removed
65+
}
66+
}
67+
}
68+
69+
// RecentTerminationsSince returns the number of terminations since the given timestamp.
70+
func (s MemberStatus) RecentTerminationsSince(timestamp time.Time) int {
71+
count := 0
72+
for idx := len(s.RecentTerminations) - 1; idx >= 0; idx-- {
73+
if s.RecentTerminations[idx].Time.Before(timestamp) {
74+
// This termination is before the timestamp, so we're done
75+
return count
76+
}
77+
count++
78+
}
79+
return count
3880
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2018 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
// Author Ewout Prangsma
21+
//
22+
23+
package v1alpha
24+
25+
import (
26+
"testing"
27+
"time"
28+
29+
"github.com/stretchr/testify/assert"
30+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31+
)
32+
33+
// TestMemberStatusRecentTerminations tests the functions related to MemberStatus.RecentTerminations.
34+
func TestMemberStatusRecentTerminations(t *testing.T) {
35+
relTime := func(delta time.Duration) metav1.Time {
36+
return metav1.Time{Time: time.Now().Add(delta)}
37+
}
38+
39+
s := MemberStatus{}
40+
assert.Equal(t, 0, s.RecentTerminationsSince(time.Now().Add(-time.Hour)))
41+
assert.Equal(t, 0, s.RemoveTerminationsBefore(time.Now()))
42+
43+
s.RecentTerminations = []metav1.Time{metav1.Now()}
44+
assert.Equal(t, 1, s.RecentTerminationsSince(time.Now().Add(-time.Minute)))
45+
assert.Equal(t, 0, s.RecentTerminationsSince(time.Now().Add(time.Minute)))
46+
assert.Equal(t, 0, s.RemoveTerminationsBefore(time.Now().Add(-time.Hour)))
47+
48+
s.RecentTerminations = []metav1.Time{relTime(-time.Hour), relTime(-time.Minute), relTime(time.Minute)}
49+
assert.Equal(t, 3, s.RecentTerminationsSince(time.Now().Add(-time.Hour*2)))
50+
assert.Equal(t, 2, s.RecentTerminationsSince(time.Now().Add(-time.Minute*2)))
51+
assert.Equal(t, 2, s.RemoveTerminationsBefore(time.Now()))
52+
assert.Len(t, s.RecentTerminations, 1)
53+
}

pkg/apis/deployment/v1alpha/zz_generated.deepcopy.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,13 @@ func (in *MemberStatus) DeepCopyInto(out *MemberStatus) {
371371
(*in)[i].DeepCopyInto(&(*out)[i])
372372
}
373373
}
374+
if in.RecentTerminations != nil {
375+
in, out := &in.RecentTerminations, &out.RecentTerminations
376+
*out = make([]v1.Time, len(*in))
377+
for i := range *in {
378+
(*in)[i].DeepCopyInto(&(*out)[i])
379+
}
380+
}
374381
return
375382
}
376383

pkg/apis/storage/v1alpha/local_storage_spec.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ func (s LocalStorageSpec) Validate() error {
4545
if len(s.LocalPath) == 0 {
4646
return maskAny(errors.Wrapf(ValidationError, "localPath cannot be empty"))
4747
}
48+
for _, p := range s.LocalPath {
49+
if len(p) == 0 {
50+
return maskAny(errors.Wrapf(ValidationError, "localPath cannot contain empty strings"))
51+
}
52+
}
4853
return nil
4954
}
5055

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2018 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
// Author Jan Christoph Uhde
21+
//
22+
23+
package v1alpha
24+
25+
import (
26+
"testing"
27+
28+
//"github.com/pkg/errors"
29+
"github.com/stretchr/testify/assert"
30+
)
31+
32+
// Test creation of local storage spec
33+
func TestLocalStorageSpecCreation(t *testing.T) {
34+
35+
class := StorageClassSpec{"SpecName", true}
36+
local := LocalStorageSpec{StorageClass: class, LocalPath: []string{""}}
37+
assert.Error(t, local.Validate())
38+
39+
class = StorageClassSpec{"spec-name", true}
40+
local = LocalStorageSpec{StorageClass: class, LocalPath: []string{""}}
41+
assert.Error(t, local.Validate(), "should fail as the empty sting is not a valid path")
42+
43+
class = StorageClassSpec{"spec-name", true}
44+
local = LocalStorageSpec{StorageClass: class, LocalPath: []string{}}
45+
assert.True(t, IsValidation(local.Validate()))
46+
}
47+
48+
// Test reset of local storage spec
49+
func TestLocalStorageSpecReset(t *testing.T) {
50+
class := StorageClassSpec{"spec-name", true}
51+
source := LocalStorageSpec{StorageClass: class, LocalPath: []string{"/a/path", "/another/path"}}
52+
target := LocalStorageSpec{}
53+
resetImmutableFieldsResult := source.ResetImmutableFields(&target)
54+
expected := []string{"storageClass.name", "localPath"}
55+
assert.Equal(t, expected, resetImmutableFieldsResult)
56+
assert.Equal(t, source.LocalPath, target.LocalPath)
57+
assert.Equal(t, source.StorageClass.Name, target.StorageClass.Name)
58+
}

0 commit comments

Comments
 (0)