diff --git a/api/v1alpha1/rpaasinstance.go b/api/v1alpha1/rpaasinstance.go index 4bd1e0fdf..5b983a72a 100644 --- a/api/v1alpha1/rpaasinstance.go +++ b/api/v1alpha1/rpaasinstance.go @@ -10,10 +10,56 @@ import ( ) const ( - teamOwnerLabel = "rpaas.extensions.tsuru.io/team-owner" - clusterNameLabel = "rpaas.extensions.tsuru.io/cluster-name" + DefaultLabelKeyPrefix = "rpaas.extensions.tsuru.io" + RpaasOperatorInstanceNameLabelKey = DefaultLabelKeyPrefix + "/instance-name" + RpaasOperatorServiceNameLabelKey = DefaultLabelKeyPrefix + "/service-name" + RpaasOperatorPlanNameLabelKey = DefaultLabelKeyPrefix + "/plan-name" + RpaasOperatorTeamOwnerLabelKey = DefaultLabelKeyPrefix + "/team-owner" + RpaasOperatorClusterNameLabelKey = DefaultLabelKeyPrefix + "/cluster-name" + + LegacyRpaasOperatorInstanceNameLabelKey = "rpaas_instance" + LegacyRpaasOperatorServiceNameLabelKey = "rpaas_service" ) +func (i *RpaasInstance) GetBaseLabels(labels map[string]string) map[string]string { + return mergeMap(map[string]string{ + LegacyRpaasOperatorInstanceNameLabelKey: i.Name, + LegacyRpaasOperatorServiceNameLabelKey: i.Labels[RpaasOperatorServiceNameLabelKey], + RpaasOperatorInstanceNameLabelKey: i.Name, + RpaasOperatorServiceNameLabelKey: i.Labels[RpaasOperatorServiceNameLabelKey], + RpaasOperatorPlanNameLabelKey: i.Spec.PlanName, + RpaasOperatorTeamOwnerLabelKey: i.Labels[RpaasOperatorTeamOwnerLabelKey], + }, labels) +} + +func (i *RpaasInstance) TeamOwner() string { + return i.Labels[RpaasOperatorTeamOwnerLabelKey] +} + +func (i *RpaasInstance) ClusterName() string { + return i.Labels[RpaasOperatorClusterNameLabelKey] +} + +func (i *RpaasInstance) SetTeamOwner(team string) { + newLabels := map[string]string{RpaasOperatorTeamOwnerLabelKey: team} + i.appendNewLabels(newLabels) +} + +func (i *RpaasInstance) SetClusterName(clusterName string) { + newLabels := map[string]string{RpaasOperatorClusterNameLabelKey: clusterName} + i.appendNewLabels(newLabels) +} + +func (i *RpaasInstance) BelongsToCluster(clusterName string) bool { + instanceCluster := i.Labels[RpaasOperatorClusterNameLabelKey] + + if instanceCluster == "" { + return false + } + + return clusterName == instanceCluster +} + func (i *RpaasInstance) CertManagerRequests() (reqs []CertManager) { if i == nil || i.Spec.DynamicCertificates == nil { return @@ -59,36 +105,12 @@ func (c *CertManager) dnsNames(i *RpaasInstance) (names []string) { return } -func (i *RpaasInstance) SetTeamOwner(team string) { - newLabels := map[string]string{teamOwnerLabel: team} - i.appendNewLabels(newLabels) -} - -func (i *RpaasInstance) SetClusterName(clusterName string) { - newLabels := map[string]string{clusterNameLabel: clusterName} - i.appendNewLabels(newLabels) -} - -func (i *RpaasInstance) BelongsToCluster(clusterName string) bool { - instanceCluster := i.Labels[clusterNameLabel] - - if instanceCluster == "" { - return false - } - - return clusterName == instanceCluster -} - func (i *RpaasInstance) appendNewLabels(newLabels map[string]string) { i.Labels = mergeMap(i.Labels, newLabels) i.Annotations = mergeMap(i.Annotations, newLabels) i.Spec.PodTemplate.Labels = mergeMap(i.Spec.PodTemplate.Labels, newLabels) } -func (i *RpaasInstance) TeamOwner() string { - return i.Labels[teamOwnerLabel] -} - func mergeMap(a, b map[string]string) map[string]string { if a == nil { return b diff --git a/api/v1alpha1/rpaasinstance_test.go b/api/v1alpha1/rpaasinstance_test.go index ded329f47..3fe336d6f 100644 --- a/api/v1alpha1/rpaasinstance_test.go +++ b/api/v1alpha1/rpaasinstance_test.go @@ -14,13 +14,13 @@ import ( func Test_SetTeamOwner(t *testing.T) { instance := &RpaasInstance{} instance.SetTeamOwner("team-one") - expected := map[string]string{teamOwnerLabel: "team-one"} + expected := map[string]string{RpaasOperatorTeamOwnerLabelKey: "team-one"} assert.Equal(t, expected, instance.Labels) assert.Equal(t, expected, instance.Annotations) assert.Equal(t, expected, instance.Spec.PodTemplate.Labels) instance.SetTeamOwner("team-two") - expected = map[string]string{teamOwnerLabel: "team-two"} + expected = map[string]string{RpaasOperatorTeamOwnerLabelKey: "team-two"} assert.Equal(t, expected, instance.Labels) assert.Equal(t, expected, instance.Annotations) assert.Equal(t, expected, instance.Spec.PodTemplate.Labels) @@ -28,11 +28,9 @@ func Test_SetTeamOwner(t *testing.T) { func Test_GetTeamOwner(t *testing.T) { instance := &RpaasInstance{} - owner := instance.TeamOwner() - assert.Equal(t, "", owner) + assert.Equal(t, "", instance.TeamOwner()) instance.SetTeamOwner("team-one") - owner = instance.TeamOwner() - assert.Equal(t, "team-one", owner) + assert.Equal(t, "team-one", instance.TeamOwner()) } func Test_BelongsToCluster(t *testing.T) { @@ -43,7 +41,7 @@ func Test_BelongsToCluster(t *testing.T) { instance = &RpaasInstance{ ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{ - clusterNameLabel: "cluster01", + RpaasOperatorClusterNameLabelKey: "cluster01", }, }, } @@ -104,5 +102,4 @@ func TestCertManagerRequests(t *testing.T) { DNSNamesDefault: true, }, }, instance.CertManagerRequests()) - } diff --git a/controllers/controller.go b/controllers/controller.go index 7908c2ccc..eb002054d 100644 --- a/controllers/controller.go +++ b/controllers/controller.go @@ -358,7 +358,7 @@ func newCronJobForSessionTickets(instance *v1alpha1.RpaasInstance) *batchv1.Cron Kind: "RpaasInstance", }), }, - Labels: labelsForRpaasInstance(instance), + Labels: instance.GetBaseLabels(nil), }, Spec: batchv1.CronJobSpec{ Schedule: minutesIntervalToSchedule(rotationInterval), @@ -366,8 +366,7 @@ func newCronJobForSessionTickets(instance *v1alpha1.RpaasInstance) *batchv1.Cron FailedJobsHistoryLimit: &jobsHistoryLimit, JobTemplate: batchv1.JobTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{}, - Labels: labelsForRpaasInstance(instance), + Labels: instance.GetBaseLabels(nil), }, Spec: batchv1.JobSpec{ Template: corev1.PodTemplateSpec{ @@ -468,7 +467,7 @@ func newSecretForTLSSessionTickets(instance *v1alpha1.RpaasInstance) (*corev1.Se ObjectMeta: metav1.ObjectMeta{ Name: secretNameForTLSSessionTickets(instance), Namespace: instance.Namespace, - Labels: labelsForRpaasInstance(instance), + Labels: instance.GetBaseLabels(nil), OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(instance, schema.GroupVersionKind{ Group: v1alpha1.GroupVersion.Group, @@ -756,7 +755,7 @@ func newKEDAScaledObject(instance *v1alpha1.RpaasInstance, nginx *nginxv1alpha1. Kind: "RpaasInstance", }), }, - Labels: labelsForRpaasInstance(instance), + Labels: instance.GetBaseLabels(nil), Annotations: map[string]string{ // NOTE: allows the KEDA controller to take over the ownership of HPA resources. "scaledobject.keda.sh/transfer-hpa-ownership": strconv.FormatBool(true), @@ -841,7 +840,7 @@ func newPDB(instance *v1alpha1.RpaasInstance, nginx *nginxv1alpha1.Nginx) (*poli Kind: "RpaasInstance", }), }, - Labels: labelsForRpaasInstance(instance), + Labels: instance.GetBaseLabels(nil), }, Spec: policyv1.PodDisruptionBudgetSpec{ MaxUnavailable: &maxUnavailable, @@ -1020,15 +1019,16 @@ func (r *RpaasInstanceReconciler) deleteOldConfig(ctx context.Context, instance func newConfigMap(instance *v1alpha1.RpaasInstance, renderedTemplate string) *corev1.ConfigMap { hash := fmt.Sprintf("%x", sha256.Sum256([]byte(renderedTemplate))) - labels := labelsForRpaasInstance(instance) - labels["type"] = "config" - labels["instance"] = instance.Name return &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + Kind: "ConfigMap", + APIVersion: "v1", + }, ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-config-%s", instance.Name, hash[:10]), Namespace: instance.Namespace, - Labels: labels, + Labels: instance.GetBaseLabels(map[string]string{"type": "config", "instance": instance.Name}), OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(instance, schema.GroupVersionKind{ Group: v1alpha1.GroupVersion.Group, @@ -1037,10 +1037,6 @@ func newConfigMap(instance *v1alpha1.RpaasInstance, renderedTemplate string) *co }), }, }, - TypeMeta: metav1.TypeMeta{ - Kind: "ConfigMap", - APIVersion: "v1", - }, Data: map[string]string{ "nginx.conf": renderedTemplate, }, @@ -1091,6 +1087,14 @@ func newNginx(instanceMergedWithFlavors *v1alpha1.RpaasInstance, plan *v1alpha1. instanceMergedWithFlavors.Spec.Service = mergeServiceWithDNS(instanceMergedWithFlavors) + if s := instanceMergedWithFlavors.Spec.Service; s != nil { + s.Labels = instanceMergedWithFlavors.GetBaseLabels(s.Labels) + } + + if ing := instanceMergedWithFlavors.Spec.Ingress; ing != nil { + ing.Labels = instanceMergedWithFlavors.GetBaseLabels(ing.Labels) + } + replicas := instanceMergedWithFlavors.Spec.Replicas if isAutoscaleEnabled(instanceMergedWithFlavors.Spec.Autoscale) { // NOTE: we should avoid changing the number of replicas as it's managed by HPA. @@ -1098,6 +1102,10 @@ func newNginx(instanceMergedWithFlavors *v1alpha1.RpaasInstance, plan *v1alpha1. } n := &nginxv1alpha1.Nginx{ + TypeMeta: metav1.TypeMeta{ + Kind: "Nginx", + APIVersion: "nginx.tsuru.io/v1alpha1", + }, ObjectMeta: metav1.ObjectMeta{ Name: instanceMergedWithFlavors.Name, Namespace: instanceMergedWithFlavors.Namespace, @@ -1108,11 +1116,7 @@ func newNginx(instanceMergedWithFlavors *v1alpha1.RpaasInstance, plan *v1alpha1. Kind: "RpaasInstance", }), }, - Labels: labelsForRpaasInstance(instanceMergedWithFlavors), - }, - TypeMeta: metav1.TypeMeta{ - Kind: "Nginx", - APIVersion: "nginx.tsuru.io/v1alpha1", + Labels: instanceMergedWithFlavors.GetBaseLabels(nil), }, Spec: nginxv1alpha1.NginxSpec{ Image: plan.Spec.Image, @@ -1251,7 +1255,7 @@ func newHPA(instance *v1alpha1.RpaasInstance, nginx *nginxv1alpha1.Nginx) *autos Kind: "RpaasInstance", }), }, - Labels: labelsForRpaasInstance(instance), + Labels: instance.GetBaseLabels(nil), }, Spec: autoscalingv2.HorizontalPodAutoscalerSpec{ ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{ @@ -1382,13 +1386,6 @@ func (_ rpaasMergoTransformers) Transformer(t reflect.Type) func(reflect.Value, return nil } -func labelsForRpaasInstance(instance *extensionsv1alpha1.RpaasInstance) map[string]string { - return map[string]string{ - "rpaas.extensions.tsuru.io/instance-name": instance.Name, - "rpaas.extensions.tsuru.io/plan-name": instance.Spec.PlanName, - } -} - func nameForCronJob(name string) string { const cronjobMaxChars = 52 diff --git a/controllers/controller_test.go b/controllers/controller_test.go index b736b6c0e..c2f045d83 100644 --- a/controllers/controller_test.go +++ b/controllers/controller_test.go @@ -95,6 +95,7 @@ func Test_newNginx(t *testing.T) { return n }, }, + "with KEDA configs set but autoscale disabled": { instance: func(i *v1alpha1.RpaasInstance) *v1alpha1.RpaasInstance { i.Spec.Replicas = func(n int32) *int32 { return &n }(15) @@ -112,6 +113,58 @@ func Test_newNginx(t *testing.T) { return n }, }, + + "with load balancer": { + instance: func(i *v1alpha1.RpaasInstance) *v1alpha1.RpaasInstance { + i.Spec.Service = &nginxv1alpha1.NginxService{ + Type: corev1.ServiceTypeLoadBalancer, + Labels: map[string]string{ + "foo": "bar", + }, + } + return i + }, + expected: func(n *nginxv1alpha1.Nginx) *nginxv1alpha1.Nginx { + n.Spec.Service = &nginxv1alpha1.NginxService{ + Type: corev1.ServiceTypeLoadBalancer, + Labels: map[string]string{ + "rpaas_instance": "my-instance", + "rpaas_service": "rpaasv2", + "rpaas.extensions.tsuru.io/instance-name": "my-instance", + "rpaas.extensions.tsuru.io/service-name": "rpaasv2", + "rpaas.extensions.tsuru.io/team-owner": "my-team", + "rpaas.extensions.tsuru.io/plan-name": "my-plan", + "foo": "bar", + }, + } + return n + }, + }, + + "with ingress provided": { + instance: func(i *v1alpha1.RpaasInstance) *v1alpha1.RpaasInstance { + i.Spec.Ingress = &nginxv1alpha1.NginxIngress{ + Labels: map[string]string{ + "foo": "bar", + }, + } + return i + }, + expected: func(n *nginxv1alpha1.Nginx) *nginxv1alpha1.Nginx { + n.Spec.Ingress = &nginxv1alpha1.NginxIngress{ + Labels: map[string]string{ + "rpaas_instance": "my-instance", + "rpaas_service": "rpaasv2", + "rpaas.extensions.tsuru.io/instance-name": "my-instance", + "rpaas.extensions.tsuru.io/service-name": "rpaasv2", + "rpaas.extensions.tsuru.io/team-owner": "my-team", + "rpaas.extensions.tsuru.io/plan-name": "my-plan", + "foo": "bar", + }, + } + return n + }, + }, } for name, tt := range tests { @@ -120,6 +173,16 @@ func Test_newNginx(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "my-instance", Namespace: "rpaasv2", + Labels: map[string]string{ + "rpaas_instance": "my-instance", + "rpaas_service": "rpaasv2", + "rpaas.extensions.tsuru.io/instance-name": "my-instance", + "rpaas.extensions.tsuru.io/service-name": "rpaasv2", + "rpaas.extensions.tsuru.io/team-owner": "my-team", + }, + Annotations: map[string]string{ + "rpaas.extensions.tsuru.io/team-owner": "my-team", + }, }, Spec: v1alpha1.RpaasInstanceSpec{ PlanName: "my-plan", @@ -155,8 +218,12 @@ func Test_newNginx(t *testing.T) { Name: "my-instance", Namespace: "rpaasv2", Labels: map[string]string{ + "rpaas_instance": "my-instance", + "rpaas_service": "rpaasv2", "rpaas.extensions.tsuru.io/instance-name": "my-instance", + "rpaas.extensions.tsuru.io/service-name": "rpaasv2", "rpaas.extensions.tsuru.io/plan-name": "my-plan", + "rpaas.extensions.tsuru.io/team-owner": "my-team", }, OwnerReferences: []metav1.OwnerReference{{ APIVersion: "extensions.tsuru.io/v1alpha1", @@ -177,9 +244,7 @@ func Test_newNginx(t *testing.T) { if tt.expected != nil { nginx = tt.expected(nginx) } - - got := newNginx(instance, plan, cm) - assert.Equal(t, nginx, got) + assert.Equal(t, nginx, newNginx(instance, plan, cm)) }) } } @@ -580,8 +645,12 @@ func Test_reconcileHPA(t *testing.T) { }, ResourceVersion: "1", Labels: map[string]string{ + "rpaas_instance": "my-instance", + "rpaas_service": "", "rpaas.extensions.tsuru.io/instance-name": "my-instance", + "rpaas.extensions.tsuru.io/service-name": "", "rpaas.extensions.tsuru.io/plan-name": "my-plan", + "rpaas.extensions.tsuru.io/team-owner": "", }, }, } @@ -605,8 +674,12 @@ func Test_reconcileHPA(t *testing.T) { }, ResourceVersion: "1", Labels: map[string]string{ + "rpaas_instance": "my-instance", + "rpaas_service": "", "rpaas.extensions.tsuru.io/instance-name": "my-instance", + "rpaas.extensions.tsuru.io/service-name": "", "rpaas.extensions.tsuru.io/plan-name": "my-plan", + "rpaas.extensions.tsuru.io/team-owner": "", }, Annotations: map[string]string{ "scaledobject.keda.sh/transfer-hpa-ownership": "true", @@ -1131,6 +1204,14 @@ func Test_reconcilePDB(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "my-instance", Namespace: "rpaasv2", + Labels: map[string]string{ + "rpaas_instance": "my-instance", + "rpaas_service": "", + "rpaas.extensions.tsuru.io/instance-name": "my-instance", + "rpaas.extensions.tsuru.io/service-name": "", + "rpaas.extensions.tsuru.io/plan-name": "", + "rpaas.extensions.tsuru.io/team-owner": "", + }, }, Status: nginxv1alpha1.NginxStatus{ PodSelector: "nginx.tsuru.io/resource-name=my-instance", @@ -1149,8 +1230,12 @@ func Test_reconcilePDB(t *testing.T) { Name: "my-instance", Namespace: "rpaasv2", Labels: map[string]string{ + "rpaas_instance": "my-instance", + "rpaas_service": "", "rpaas.extensions.tsuru.io/instance-name": "my-instance", + "rpaas.extensions.tsuru.io/service-name": "", "rpaas.extensions.tsuru.io/plan-name": "", + "rpaas.extensions.tsuru.io/team-owner": "", }, ResourceVersion: "1", OwnerReferences: []metav1.OwnerReference{ @@ -1188,6 +1273,14 @@ func Test_reconcilePDB(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "my-instance", Namespace: "rpaasv2", + Labels: map[string]string{ + "rpaas_instance": "my-instance", + "rpaas_service": "", + "rpaas.extensions.tsuru.io/instance-name": "my-instance", + "rpaas.extensions.tsuru.io/service-name": "", + "rpaas.extensions.tsuru.io/plan-name": "", + "rpaas.extensions.tsuru.io/team-owner": "", + }, }, Status: nginxv1alpha1.NginxStatus{ PodSelector: "nginx.tsuru.io/resource-name=my-instance", @@ -1206,8 +1299,12 @@ func Test_reconcilePDB(t *testing.T) { Name: "my-instance", Namespace: "rpaasv2", Labels: map[string]string{ + "rpaas_instance": "my-instance", + "rpaas_service": "", "rpaas.extensions.tsuru.io/instance-name": "my-instance", + "rpaas.extensions.tsuru.io/service-name": "", "rpaas.extensions.tsuru.io/plan-name": "", + "rpaas.extensions.tsuru.io/team-owner": "", }, ResourceVersion: "1", OwnerReferences: []metav1.OwnerReference{ @@ -1249,6 +1346,14 @@ func Test_reconcilePDB(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "another-instance", Namespace: "rpaasv2", + Labels: map[string]string{ + "rpaas_instance": "another-instance", + "rpaas_service": "", + "rpaas.extensions.tsuru.io/instance-name": "another-instance", + "rpaas.extensions.tsuru.io/service-name": "", + "rpaas.extensions.tsuru.io/plan-name": "", + "rpaas.extensions.tsuru.io/team-owner": "", + }, }, Status: nginxv1alpha1.NginxStatus{ PodSelector: "nginx.tsuru.io/resource-name=another-instance", @@ -1267,8 +1372,12 @@ func Test_reconcilePDB(t *testing.T) { Name: "another-instance", Namespace: "rpaasv2", Labels: map[string]string{ + "rpaas_instance": "another-instance", + "rpaas_service": "", "rpaas.extensions.tsuru.io/instance-name": "another-instance", + "rpaas.extensions.tsuru.io/service-name": "", "rpaas.extensions.tsuru.io/plan-name": "", + "rpaas.extensions.tsuru.io/team-owner": "", }, ResourceVersion: "1000", OwnerReferences: []metav1.OwnerReference{ @@ -1309,6 +1418,14 @@ func Test_reconcilePDB(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "another-instance", Namespace: "rpaasv2", + Labels: map[string]string{ + "rpaas_instance": "another-instance", + "rpaas_service": "", + "rpaas.extensions.tsuru.io/instance-name": "another-instance", + "rpaas.extensions.tsuru.io/service-name": "", + "rpaas.extensions.tsuru.io/plan-name": "", + "rpaas.extensions.tsuru.io/team-owner": "", + }, }, Status: nginxv1alpha1.NginxStatus{ PodSelector: "nginx.tsuru.io/resource-name=another-instance", @@ -1337,6 +1454,14 @@ func Test_reconcilePDB(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "my-instance", Namespace: "rpaasv2", + Labels: map[string]string{ + "rpaas_instance": "my-instance", + "rpaas_service": "", + "rpaas.extensions.tsuru.io/instance-name": "my-instance", + "rpaas.extensions.tsuru.io/service-name": "", + "rpaas.extensions.tsuru.io/plan-name": "", + "rpaas.extensions.tsuru.io/team-owner": "", + }, }, Status: nginxv1alpha1.NginxStatus{ PodSelector: "nginx.tsuru.io/resource-name=my-instance", @@ -1355,8 +1480,12 @@ func Test_reconcilePDB(t *testing.T) { Name: "my-instance", Namespace: "rpaasv2", Labels: map[string]string{ + "rpaas_instance": "my-instance", + "rpaas_service": "", "rpaas.extensions.tsuru.io/instance-name": "my-instance", + "rpaas.extensions.tsuru.io/service-name": "", "rpaas.extensions.tsuru.io/plan-name": "", + "rpaas.extensions.tsuru.io/team-owner": "", }, ResourceVersion: "1", OwnerReferences: []metav1.OwnerReference{ @@ -1394,6 +1523,14 @@ func Test_reconcilePDB(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "my-instance", Namespace: "rpaasv2", + Labels: map[string]string{ + "rpaas_instance": "my-instance", + "rpaas_service": "", + "rpaas.extensions.tsuru.io/instance-name": "another-instance", + "rpaas.extensions.tsuru.io/service-name": "", + "rpaas.extensions.tsuru.io/plan-name": "", + "rpaas.extensions.tsuru.io/team-owner": "", + }, }, Status: nginxv1alpha1.NginxStatus{ PodSelector: "nginx.tsuru.io/resource-name=my-instance", @@ -1422,6 +1559,14 @@ func Test_reconcilePDB(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "my-instance", Namespace: "rpaasv2", + Labels: map[string]string{ + "rpaas_instance": "my-instance", + "rpaas_service": "", + "rpaas.extensions.tsuru.io/instance-name": "my-instance", + "rpaas.extensions.tsuru.io/service-name": "", + "rpaas.extensions.tsuru.io/plan-name": "", + "rpaas.extensions.tsuru.io/team-owner": "", + }, }, }, assert: func(t *testing.T, c client.Client) {