Skip to content

Commit

Permalink
feat: Limit the availability of multiple TabletPool instances to Exte…
Browse files Browse the repository at this point in the history
…rnalDatastore

Signed-off-by: Yohei Yoshimuta <[email protected]>
  • Loading branch information
yoheimuta committed Jun 21, 2023
1 parent a042c49 commit 3695721
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 38 deletions.
3 changes: 2 additions & 1 deletion docs/api/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7075,7 +7075,8 @@ <h3 id="planetscale.com/v2.VitessShardTabletPool">VitessShardTabletPool
<p>Name is the pool&rsquo;s unique name within the (cell,type) pair.
This field is optional, and defaults to an empty.
Assigning different names to this field enables the existence of multiple pools with a specific tablet type in a given cell,
which can be beneficial for unmanaged tablets.</p>
which can be beneficial for unmanaged tablets.
Hence, you must specify ExternalDatastore when assigning a name to this field.</p>
</td>
</tr>
<tr>
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/planetscale/v2/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const (
// TabletTypeLabel is the key for identifying the Vitess target tablet type for a Pod.
TabletTypeLabel = LabelPrefix + "/" + "tablet-type"
// TabletPoolNameLabel is the key for identifying the Vitess target pool name within the (cell,type) pair.
// This label is applicable to Vitess-unmanaged keyspaces.
TabletPoolNameLabel = LabelPrefix + "/" + "pool-name"
// TabletIndexLabel is the key for identifying the index of a Vitess tablet within its pool.
TabletIndexLabel = LabelPrefix + "/" + "tablet-index"
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/planetscale/v2/vitessshard_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ type VitessShardTabletPool struct {
// This field is optional, and defaults to an empty.
// Assigning different names to this field enables the existence of multiple pools with a specific tablet type in a given cell,
// which can be beneficial for unmanaged tablets.
// Hence, you must specify ExternalDatastore when assigning a name to this field.
// +kubebuilder:default=""
Name string `json:"name,omitempty"`

Expand Down
6 changes: 4 additions & 2 deletions pkg/controller/vitessshard/reconcile_tablets.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ func vttabletSpecs(vts *planetscalev2.VitessShard, parentLabels map[string]strin
}

// If TabletPools has multiple pools within the same (cell,type) pair, we need to add a pool name to the UID generator.
if 0 < len(pool.Name) {
if pool.ExternalDatastore != nil && 0 < len(pool.Name) {
tabletAlias.Uid = vttablet.UIDWithPoolName(pool.Cell, keyspaceName, vts.Spec.KeyRange, pool.Type, uint32(tabletIndex), pool.Name)
}

Expand All @@ -297,8 +297,10 @@ func vttabletSpecs(vts *planetscalev2.VitessShard, parentLabels map[string]strin
labels[planetscalev2.CellLabel] = tabletAlias.Cell
labels[planetscalev2.TabletUidLabel] = strconv.FormatUint(uint64(tabletAlias.Uid), 10)
labels[planetscalev2.TabletTypeLabel] = string(pool.Type)
labels[planetscalev2.TabletPoolNameLabel] = pool.Name
labels[planetscalev2.TabletIndexLabel] = strconv.FormatUint(uint64(tabletIndex), 10)
if pool.ExternalDatastore != nil {
labels[planetscalev2.TabletPoolNameLabel] = pool.Name
}

// Merge ExtraVitessFlags into the tablet spec ExtraFlags field.
extraFlags := make(map[string]string)
Expand Down
93 changes: 58 additions & 35 deletions test/integration/vitesscluster/vitesscluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,6 @@ spec:
resources:
requests:
storage: 1Gi
- cell: cell2
type: rdonly
name: unmanaged-replica-2
replicas: 3
mysqld: {}
dataVolumeClaimTemplate:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 1Gi
- equal:
parts: 1
shardTemplate:
Expand All @@ -87,11 +77,28 @@ spec:
type: replica
replicas: 3
mysqld: {}
dataVolumeClaimTemplate:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 1Gi
externalDatastore:
port: 3306
credentialsSecret:
name: cluster-config
key: db_credentials.json
- cell: cell3
type: rdonly
replicas: 3
externalDatastore:
port: 3307
credentialsSecret:
name: cluster-config
key: db_credentials.json
- cell: cell3
type: rdonly
replicas: 3
name: unmanaged-replica-2
externalDatastore:
port: 3308
credentialsSecret:
name: cluster-config
key: db_credentials.json
backup:
locations:
- name: vbs1
Expand Down Expand Up @@ -191,9 +198,9 @@ func verifyBasicVitessKeyspace(f *framework.Fixture, ns, cluster, keyspace strin
f.MustGet(ns, names.JoinWithConstraints(names.DefaultConstraints, cluster, keyspace), &planetscalev2.VitessKeyspace{})

// VitessKeyspaces create VitessShards.
verifyBasicVitessShard(f, ns, cluster, keyspace, "x-80", []int{3, 3, 3, 0})
verifyBasicVitessShard(f, ns, cluster, keyspace, "80-x", []int{3, 3, 3, 0})
verifyBasicVitessShard(f, ns, cluster, keyspace, "x-x", []int{0, 0, 0, 3})
verifyBasicVitessShard(f, ns, cluster, keyspace, "x-80", []int{3, 3})
verifyBasicVitessShard(f, ns, cluster, keyspace, "80-x", []int{3, 3})
verifyBasicVitessShardExternal(f, ns, cluster, keyspace, "x-x", []int{3, 3, 3})
}

func verifyBasicVitessShard(f *framework.Fixture, ns, cluster, keyspace, shard string, expectedTabletCount []int) {
Expand All @@ -202,20 +209,12 @@ func verifyBasicVitessShard(f *framework.Fixture, ns, cluster, keyspace, shard s
// VitessShard creates vttablet Pods.
cell1Pods := f.ExpectPods(&client.ListOptions{
Namespace: ns,
LabelSelector: tabletPodSelector(cluster, keyspace, shard, "cell1", "replica", ""),
LabelSelector: tabletPodSelector(cluster, keyspace, shard, "cell1", "replica"),
}, expectedTabletCount[0])
cell2Pods := f.ExpectPods(&client.ListOptions{
Namespace: ns,
LabelSelector: tabletPodSelector(cluster, keyspace, shard, "cell2", "rdonly", ""),
LabelSelector: tabletPodSelector(cluster, keyspace, shard, "cell2", "rdonly"),
}, expectedTabletCount[1])
cell2_1_Pods := f.ExpectPods(&client.ListOptions{
Namespace: ns,
LabelSelector: tabletPodSelector(cluster, keyspace, shard, "cell2", "rdonly", "unmanaged-replica-2"),
}, expectedTabletCount[2])
cell3Pods := f.ExpectPods(&client.ListOptions{
Namespace: ns,
LabelSelector: tabletPodSelector(cluster, keyspace, shard, "cell3", "replica", ""),
}, expectedTabletCount[3])

// Each vttablet Pod should have a PVC.
for i := range cell1Pods.Items {
Expand All @@ -224,19 +223,43 @@ func verifyBasicVitessShard(f *framework.Fixture, ns, cluster, keyspace, shard s
for i := range cell2Pods.Items {
f.MustGet(ns, cell2Pods.Items[i].Name, &corev1.PersistentVolumeClaim{})
}
for i := range cell2_1_Pods.Items {
f.MustGet(ns, cell2_1_Pods.Items[i].Name, &corev1.PersistentVolumeClaim{})
}
for i := range cell3Pods.Items {
f.MustGet(ns, cell3Pods.Items[i].Name, &corev1.PersistentVolumeClaim{})
}

// VitessShard creates vtbackup-init Pod/PVC.
f.MustGet(ns, names.JoinWithConstraints(names.DefaultConstraints, cluster, keyspace, shard, "vtbackup", "init"), &corev1.Pod{})
f.MustGet(ns, names.JoinWithConstraints(names.DefaultConstraints, cluster, keyspace, shard, "vtbackup", "init"), &corev1.PersistentVolumeClaim{})
}

func tabletPodSelector(cluster, keyspace, shard, cell, tabletType, poolName string) apilabels.Selector {
func verifyBasicVitessShardExternal(f *framework.Fixture, ns, cluster, keyspace, shard string, expectedTabletCount []int) {
f.MustGet(ns, names.JoinWithConstraints(names.DefaultConstraints, cluster, keyspace, shard), &planetscalev2.VitessShard{})

// VitessShard creates vttablet Pods.
f.ExpectPods(&client.ListOptions{
Namespace: ns,
LabelSelector: tabletPodExternalSelector(cluster, keyspace, shard, "cell3", "replica", ""),
}, expectedTabletCount[0])
f.ExpectPods(&client.ListOptions{
Namespace: ns,
LabelSelector: tabletPodExternalSelector(cluster, keyspace, shard, "cell3", "rdonly", ""),
}, expectedTabletCount[1])
f.ExpectPods(&client.ListOptions{
Namespace: ns,
LabelSelector: tabletPodExternalSelector(cluster, keyspace, shard, "cell3", "rdonly", "unmanaged-replica-2"),
}, expectedTabletCount[2])
}

func tabletPodSelector(cluster, keyspace, shard, cell, tabletType string) apilabels.Selector {
// This intentionally does NOT use any shared constants because we want the
// test to fail if the labels change, since that's a breaking change.
return apilabels.Set{
"planetscale.com/cluster": cluster,
"planetscale.com/keyspace": keyspace,
"planetscale.com/shard": shard,
"planetscale.com/cell": cell,
"planetscale.com/tablet-type": tabletType,
}.AsSelector()
}

func tabletPodExternalSelector(cluster, keyspace, shard, cell, tabletType, poolName string) apilabels.Selector {
// This intentionally does NOT use any shared constants because we want the
// test to fail if the labels change, since that's a breaking change.
return apilabels.Set{
Expand Down

0 comments on commit 3695721

Please sign in to comment.