Skip to content
This repository was archived by the owner on Apr 4, 2023. It is now read-only.

Commit 4eb5cb2

Browse files
authored
Merge pull request #321 from wallrj/320-version-validation
Add validation to only allow Cassandra major version 3
2 parents e8fb08d + 635c5fc commit 4eb5cb2

File tree

30 files changed

+1617
-78
lines changed

30 files changed

+1617
-78
lines changed

Gopkg.lock

Lines changed: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# Gopkg.toml example
32
#
43
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md

docs/cassandra.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,8 @@ Navigator will add C* nodes, one at a time, until the desired number of nodes is
237237
and `Best way to add multiple nodes to existing cassandra cluster <https://stackoverflow.com/questions/37283424/best-way-to-add-multiple-nodes-to-existing-cassandra-cluster>`_.
238238

239239
You can look at ``CassandraCluster.Status.NodePools[<nodepoolname>].ReadyReplicas`` to see the current number of healthy C* nodes in each ``nodepool``.
240+
241+
Supported Versions
242+
------------------
243+
244+
Navigator only supports Cassandra major version 3.

hack/update-client-gen.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,11 @@ ${CODEGEN_PKG}/generate-internal-groups.sh all \
1414
navigator:v1alpha1 \
1515
--output-base "${GOPATH}/src/" \
1616
--go-header-file ${SCRIPT_ROOT}/hack/boilerplate.go.txt
17+
18+
echo "Generating other deepcopy funcs"
19+
${GOPATH}/bin/deepcopy-gen \
20+
--input-dirs github.com/jetstack/navigator/pkg/api/version \
21+
-O zz_generated.deepcopy \
22+
--bounding-dirs github.com/jetstack/navigator/pkg/api/version \
23+
--output-base "${GOPATH}/src/" \
24+
--go-header-file ${SCRIPT_ROOT}/hack/boilerplate.go.txt

internal/test/util/generate/generate.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
core "k8s.io/api/core/v1"
77
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
88

9+
"github.com/jetstack/navigator/pkg/api/version"
910
"github.com/jetstack/navigator/pkg/apis/navigator/v1alpha1"
1011
)
1112

@@ -129,6 +130,9 @@ func CassandraCluster(c CassandraClusterConfig) *v1alpha1.CassandraCluster {
129130
Name: c.Name,
130131
Namespace: c.Namespace,
131132
},
133+
Spec: v1alpha1.CassandraClusterSpec{
134+
Version: *version.New("3.11.2"),
135+
},
132136
}
133137
}
134138

pkg/cassandra/version/version.go renamed to pkg/api/version/version.go

Lines changed: 30 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@ package version
22

33
import (
44
"encoding/json"
5-
"fmt"
65
"strconv"
7-
"strings"
86

9-
"github.com/coreos/go-semver/semver"
7+
semver "github.com/hashicorp/go-version"
108
)
119

1210
// Version represents a Cassandra database server version.
@@ -23,9 +21,11 @@ import (
2321
// This also fixes the missing Patch number and stores the version internally as a semver.
2422
// It also keeps a reference to the original version string so that we can report that in our API.
2523
// So that the version reported in our API matches the version that an administrator expects.
24+
//
25+
// +k8s:deepcopy-gen=true
2626
type Version struct {
2727
versionString string
28-
semver semver.Version
28+
semver *semver.Version
2929
}
3030

3131
func New(s string) *Version {
@@ -37,10 +37,28 @@ func New(s string) *Version {
3737
return v
3838
}
3939

40+
func (v *Version) set(s string) error {
41+
sv, err := semver.NewVersion(s)
42+
if err != nil {
43+
return err
44+
}
45+
v.versionString = s
46+
v.semver = sv
47+
return nil
48+
}
49+
4050
func (v *Version) Equal(versionB *Version) bool {
4151
return v.semver.Equal(versionB.semver)
4252
}
4353

54+
func (v Version) String() string {
55+
return v.versionString
56+
}
57+
58+
func (v *Version) Semver() *semver.Version {
59+
return v.semver
60+
}
61+
4462
func (v *Version) UnmarshalJSON(data []byte) error {
4563
s, err := strconv.Unquote(string(data))
4664
if err != nil {
@@ -49,62 +67,20 @@ func (v *Version) UnmarshalJSON(data []byte) error {
4967
return v.set(s)
5068
}
5169

52-
func (v *Version) set(cassVersionString string) error {
53-
var versionsTried []string
54-
var errorsEncountered []string
55-
56-
errorWhileParsingOriginalVersion := v.semver.Set(cassVersionString)
57-
if errorWhileParsingOriginalVersion == nil {
58-
v.versionString = cassVersionString
59-
return nil
60-
}
61-
62-
versionsTried = append(versionsTried, cassVersionString)
63-
errorsEncountered = append(errorsEncountered, errorWhileParsingOriginalVersion.Error())
64-
65-
semverString := maybeAddMissingPatchVersion(cassVersionString)
66-
if semverString != cassVersionString {
67-
errorWhileParsingSemverVersion := v.semver.Set(semverString)
68-
if errorWhileParsingSemverVersion == nil {
69-
v.versionString = cassVersionString
70-
return nil
71-
}
72-
versionsTried = append(versionsTried, semverString)
73-
errorsEncountered = append(errorsEncountered, errorWhileParsingSemverVersion.Error())
74-
}
75-
76-
return fmt.Errorf(
77-
"unable to parse Cassandra version as semver. "+
78-
"Versions tried: '%s'. "+
79-
"Errors encountered: '%s'.",
80-
strings.Join(versionsTried, "','"),
81-
strings.Join(errorsEncountered, "','"),
82-
)
83-
}
84-
8570
var _ json.Unmarshaler = &Version{}
8671

87-
func maybeAddMissingPatchVersion(v string) string {
88-
mmpAndLabels := strings.SplitN(v, "-", 2)
89-
mmp := mmpAndLabels[0]
90-
mmpParts := strings.SplitN(mmp, ".", 3)
91-
if len(mmpParts) == 2 {
92-
mmp = mmp + ".0"
93-
}
94-
mmpAndLabels[0] = mmp
95-
return strings.Join(mmpAndLabels, "-")
96-
}
97-
98-
func (v Version) String() string {
99-
return v.versionString
100-
}
101-
10272
func (v Version) MarshalJSON() ([]byte, error) {
10373
return []byte(strconv.Quote(v.String())), nil
10474
}
10575

10676
var _ json.Marshaler = &Version{}
10777

108-
func (v Version) Semver() string {
109-
return v.semver.String()
78+
// DeepCopy returns a deep-copy of the Version value.
79+
// If the underlying semver is a nil pointer, assume that the zero value is being copied,
80+
// and return that.
81+
func (v Version) DeepCopy() Version {
82+
if v.semver == nil {
83+
return Version{}
84+
}
85+
return *New(v.String())
11086
}

pkg/cassandra/version/version_test.go renamed to pkg/api/version/version_test.go

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package version_test
33
import (
44
"testing"
55

6-
"github.com/jetstack/navigator/pkg/cassandra/version"
6+
"github.com/jetstack/navigator/pkg/api/version"
77
)
88

99
func TestUnmarshalJSON(t *testing.T) {
@@ -21,10 +21,6 @@ func TestUnmarshalJSON(t *testing.T) {
2121
s: `"0.0.x"`,
2222
expectErr: true,
2323
},
24-
"incomplete semver": {
25-
s: `"3"`,
26-
expectErr: true,
27-
},
2824
"cassandra partial invalid semver with labels": {
2925
s: `"X.Y-foo+bar"`,
3026
expectErr: true,
@@ -33,6 +29,12 @@ func TestUnmarshalJSON(t *testing.T) {
3329
s: `"X.Y.0-"`,
3430
expectErr: true,
3531
},
32+
// Cassandra versions always include a minor version but Hashicorp
33+
// go-version (which we currently use for parsing) doesn't require it.
34+
"partial semver": {
35+
s: `"3"`,
36+
v: version.New("3.0.0"),
37+
},
3638
"cassandra partial semver": {
3739
s: `"3.9"`,
3840
v: version.New("3.9.0"),
@@ -91,3 +93,18 @@ func TestUnmarshalJSON(t *testing.T) {
9193
)
9294
}
9395
}
96+
97+
func TestDeepCopy(t *testing.T) {
98+
t.Run(
99+
"zero value",
100+
func(t *testing.T) {
101+
t.Log(version.Version{}.DeepCopy())
102+
},
103+
)
104+
t.Run(
105+
"validated version",
106+
func(t *testing.T) {
107+
t.Log(version.New("3.11.2").DeepCopy())
108+
},
109+
)
110+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// +build !ignore_autogenerated
2+
3+
/*
4+
Copyright 2018 Jetstack Ltd.
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+
19+
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
20+
21+
package version
22+
23+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
24+
func (in *Version) DeepCopyInto(out *Version) {
25+
*out = in.DeepCopy()
26+
return
27+
}

pkg/apis/navigator/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"k8s.io/apimachinery/pkg/api/resource"
77
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
88

9-
"github.com/jetstack/navigator/pkg/cassandra/version"
9+
"github.com/jetstack/navigator/pkg/api/version"
1010
)
1111

1212
// In this file we define the outer containing types for the ElasticsearchCluster

pkg/apis/navigator/v1alpha1/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"k8s.io/apimachinery/pkg/api/resource"
77
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
88

9-
"github.com/jetstack/navigator/pkg/cassandra/version"
9+
"github.com/jetstack/navigator/pkg/api/version"
1010
)
1111

1212
const (

0 commit comments

Comments
 (0)