Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Elasticsearch volumes expansion #3752

Merged
merged 25 commits into from
Oct 2, 2020
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
000e05a
Remove the PVC validation webhook
sebgl Sep 15, 2020
41e750f
RBAC access to read storage classes
sebgl Sep 15, 2020
2a28b6b
Move GetClaim to a common place for reuse
sebgl Sep 15, 2020
1607903
Rename pvc.go to pvc_gc.go
sebgl Sep 15, 2020
20e51e1
Resize PVCs whose storage req has changed
sebgl Sep 15, 2020
9b24749
Delete StatefulSet for recreation on volume expansion
sebgl Sep 15, 2020
6be1279
Pass the replicas count instead of the entire sset to LimitMasterNode…
sebgl Sep 15, 2020
613e650
Take into account temporarily deleted ssets when adjusting replicas
sebgl Sep 15, 2020
607136b
Plug the volume expansion logic to the upscale phase
sebgl Sep 15, 2020
cbe0a97
Remove deprecated rolling upgrade partition strategy from upscale tests
sebgl Sep 15, 2020
8080ad7
Garbage collect PVCs after having dealt with temporarily deleted ssets
sebgl Sep 15, 2020
8872518
Use the highest existing ordinal instead of the pods count
sebgl Sep 15, 2020
f489396
Add missing license headers
sebgl Sep 15, 2020
e4fe580
Improvements from PR review
sebgl Sep 15, 2020
08c54d1
Revert "RBAC access to read storage classes"
sebgl Sep 17, 2020
aaf0b58
Remove storage class checks for rbac concerns
sebgl Sep 17, 2020
4049840
Revert "Remove the PVC validation webhook"
sebgl Sep 17, 2020
ffe8e59
Ignore storage requests changes in the pvc validation webhook
sebgl Sep 17, 2020
0793b91
Reword the pvc modification error msg
sebgl Sep 22, 2020
697f1c1
Store statefulsets to recreate in an annotation
sebgl Sep 29, 2020
55a5c77
Remove the special upscale state fix not needed anymore
sebgl Sep 30, 2020
5121657
Improvements from PR review
sebgl Sep 30, 2020
f22af15
Set a temporary ownerref on Pods while the StatefulSet is being recre…
sebgl Sep 30, 2020
e82ba2d
Fix unit tests
sebgl Oct 1, 2020
9e442b1
Fix unit tests
sebgl Oct 1, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions hack/manifest-gen/assets/charts/eck/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ RBAC permissions
- update
- patch
- delete
- apiGroups:
- storage.k8s.io
resources:
- storageclasses
verbs:
- get
- list
- watch
sebgl marked this conversation as resolved.
Show resolved Hide resolved
- apiGroups:
- apps
resources:
Expand Down
35 changes: 0 additions & 35 deletions pkg/apis/elasticsearch/v1/validations.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"net"
"strings"

apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/util/validation/field"

commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1"
Expand All @@ -29,7 +28,6 @@ const (
nodeRolesInOldVersionMsg = "node.roles setting is not available in this version of Elasticsearch"
parseStoredVersionErrMsg = "Cannot parse current Elasticsearch version. String format must be {major}.{minor}.{patch}[-{label}]"
parseVersionErrMsg = "Cannot parse Elasticsearch version. String format must be {major}.{minor}.{patch}[-{label}]"
pvcImmutableMsg = "Volume claim templates cannot be modified"
unsupportedConfigErrMsg = "Configuration setting is reserved for internal use. User-configured use is unsupported"
unsupportedUpgradeMsg = "Unsupported version upgrade path. Check the Elasticsearch documentation for supported upgrade paths."
unsupportedVersionMsg = "Unsupported version"
Expand All @@ -52,7 +50,6 @@ type updateValidation func(*Elasticsearch, *Elasticsearch) field.ErrorList
var updateValidations = []updateValidation{
noDowngrades,
validUpgradePath,
pvcModification,
sebgl marked this conversation as resolved.
Show resolved Hide resolved
}

func (es *Elasticsearch) check(validations []validation) field.ErrorList {
Expand Down Expand Up @@ -207,29 +204,6 @@ func checkNodeSetNameUniqueness(es *Elasticsearch) field.ErrorList {
return errs
}

// pvcModification ensures no PVCs are changed, as volume claim templates are immutable in stateful sets
func pvcModification(current, proposed *Elasticsearch) field.ErrorList {
var errs field.ErrorList
if current == nil || proposed == nil {
return errs
}
for i, node := range proposed.Spec.NodeSets {
currNode := getNode(node.Name, current)
if currNode == nil {
// this is a new sset, so there is nothing to check
continue
}

// ssets do not allow modifications to fields other than 'replicas', 'template', and 'updateStrategy'
// reflection isn't ideal, but okay here since the ES object does not have the status of the claims.
// Checking semantic equality here allows providing PVC storage size with different units (eg. 1Ti vs. 1024Gi).
if !apiequality.Semantic.DeepEqual(node.VolumeClaimTemplates, currNode.VolumeClaimTemplates) {
errs = append(errs, field.Invalid(field.NewPath("spec").Child("nodeSet").Index(i).Child("volumeClaimTemplates"), node.VolumeClaimTemplates, pvcImmutableMsg))
}
}
return errs
}
sebgl marked this conversation as resolved.
Show resolved Hide resolved

func noDowngrades(current, proposed *Elasticsearch) field.ErrorList {
var errs field.ErrorList
if current == nil || proposed == nil {
Expand Down Expand Up @@ -283,12 +257,3 @@ func validUpgradePath(current, proposed *Elasticsearch) field.ErrorList {
}
return errs
}

func getNode(name string, es *Elasticsearch) *NodeSet {
for i := range es.Spec.NodeSets {
if es.Spec.NodeSets[i].Name == name {
return &es.Spec.NodeSets[i]
}
}
return nil
}
262 changes: 0 additions & 262 deletions pkg/apis/elasticsearch/v1/validations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand Down Expand Up @@ -316,239 +315,6 @@ func Test_validSanIP(t *testing.T) {
}
}

func Test_pvcModified(t *testing.T) {
current := getEsCluster()

tests := []struct {
name string
current *Elasticsearch
proposed *Elasticsearch
expectErrors bool
}{
{
name: "resize fails",
current: current,
proposed: &Elasticsearch{
Spec: ElasticsearchSpec{
Version: "7.2.0",
NodeSets: []NodeSet{
{
Name: "master",
VolumeClaimTemplates: []corev1.PersistentVolumeClaim{
{
ObjectMeta: metav1.ObjectMeta{
Name: "elasticsearch-data",
},
Spec: corev1.PersistentVolumeClaimSpec{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: resource.MustParse("10Gi"),
},
},
},
},
},
},
},
},
},
expectErrors: true,
},
{
name: "same size with different unit accepted",
current: current,
proposed: &Elasticsearch{
Spec: ElasticsearchSpec{
Version: "7.2.0",
NodeSets: []NodeSet{
{
Name: "master",
VolumeClaimTemplates: []corev1.PersistentVolumeClaim{
{
ObjectMeta: metav1.ObjectMeta{
Name: "elasticsearch-data",
},
Spec: corev1.PersistentVolumeClaimSpec{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: resource.MustParse("5120Mi"),
},
},
},
},
},
},
},
},
},
expectErrors: false,
},
{
name: "same size accepted",
current: current,
proposed: &Elasticsearch{
Spec: ElasticsearchSpec{
Version: "7.2.0",
NodeSets: []NodeSet{
{
Name: "master",
VolumeClaimTemplates: []corev1.PersistentVolumeClaim{
{
ObjectMeta: metav1.ObjectMeta{
Name: "elasticsearch-data",
},
Spec: corev1.PersistentVolumeClaimSpec{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: resource.MustParse("5Gi"),
},
},
},
},
},
},
},
},
},
expectErrors: false,
},

{
name: "additional PVC fails",
current: current,
proposed: &Elasticsearch{
Spec: ElasticsearchSpec{
Version: "7.2.0",
NodeSets: []NodeSet{
{
Name: "master",
VolumeClaimTemplates: []corev1.PersistentVolumeClaim{
{
ObjectMeta: metav1.ObjectMeta{
Name: "elasticsearch-data",
},
Spec: corev1.PersistentVolumeClaimSpec{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: resource.MustParse("5Gi"),
},
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "elasticsearch-data1",
},
Spec: corev1.PersistentVolumeClaimSpec{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: resource.MustParse("5Gi"),
},
},
},
},
},
},
},
},
},
expectErrors: true,
},

{
name: "name change rejected",
current: current,
proposed: &Elasticsearch{
Spec: ElasticsearchSpec{
Version: "7.2.0",
NodeSets: []NodeSet{
{
Name: "master",
VolumeClaimTemplates: []corev1.PersistentVolumeClaim{
{
ObjectMeta: metav1.ObjectMeta{
Name: "elasticsearch-data1",
},
Spec: corev1.PersistentVolumeClaimSpec{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: resource.MustParse("5Gi"),
},
},
},
},
},
},
},
},
},
expectErrors: true,
},

{
name: "add new node set accepted",
current: current,
proposed: &Elasticsearch{
Spec: ElasticsearchSpec{
Version: "7.2.0",
NodeSets: []NodeSet{
{
Name: "master",
VolumeClaimTemplates: []corev1.PersistentVolumeClaim{
{
ObjectMeta: metav1.ObjectMeta{
Name: "elasticsearch-data",
},
Spec: corev1.PersistentVolumeClaimSpec{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: resource.MustParse("5Gi"),
},
},
},
},
},
},
{
Name: "ingest",
VolumeClaimTemplates: []corev1.PersistentVolumeClaim{
{
ObjectMeta: metav1.ObjectMeta{
Name: "elasticsearch-data",
},
Spec: corev1.PersistentVolumeClaimSpec{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: resource.MustParse("10Gi"),
},
},
},
},
},
},
},
},
},
expectErrors: false,
},

{
name: "new instance accepted",
current: nil,
proposed: current,
expectErrors: false,
},
}

for _, tt := range tests {
actual := pvcModification(tt.current, tt.proposed)
actualErrors := len(actual) > 0
if tt.expectErrors != actualErrors {
t.Errorf("failed pvcModification(). Name: %v, actual %v, wanted: %v, value: %v", tt.name, actual, tt.expectErrors, tt.proposed)
}
}
}

func TestValidation_noDowngrades(t *testing.T) {
tests := []struct {
name string
Expand Down Expand Up @@ -702,31 +468,3 @@ func es(v string) *Elasticsearch {
Spec: ElasticsearchSpec{Version: v},
}
}

// // getEsCluster returns a ES cluster test fixture
func getEsCluster() *Elasticsearch {
return &Elasticsearch{
Spec: ElasticsearchSpec{
Version: "7.2.0",
NodeSets: []NodeSet{
{
Name: "master",
VolumeClaimTemplates: []corev1.PersistentVolumeClaim{
{
ObjectMeta: metav1.ObjectMeta{
Name: "elasticsearch-data",
},
Spec: corev1.PersistentVolumeClaimSpec{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: resource.MustParse("5Gi"),
},
},
},
},
},
},
},
},
}
}
Loading