From 10b35ee41d14012dcd4f1bbdc42dbafec80c93c8 Mon Sep 17 00:00:00 2001 From: Erin Corson Date: Tue, 24 Mar 2020 15:40:10 -0600 Subject: [PATCH 1/5] add a function to convert labels to tags and filter --- pkg/helpers/labels.go | 22 +++++++++++++++++++ .../azuresqlserver_reconcile.go | 8 ++----- 2 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 pkg/helpers/labels.go diff --git a/pkg/helpers/labels.go b/pkg/helpers/labels.go new file mode 100644 index 00000000000..c4e363716f6 --- /dev/null +++ b/pkg/helpers/labels.go @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +package helpers + +import "strings" + +// LabelsToTags converts labels from a kube resource to the data structure expected by Azure for tags +func LabelsToTags(in map[string]string) (map[string]*string, [][]string) { + out := map[string]*string{} + issues := [][]string{} + for k, v := range in { + if strings.ContainsAny(k, "<>%/?\\") { + issues = append(issues, []string{k, "contains a character not allowed in Azure tags"}) + } else { + value := v + out[k] = &value + } + } + + return out, issues +} diff --git a/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver_reconcile.go b/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver_reconcile.go index e865e12d5a6..b10a88f4dc0 100644 --- a/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver_reconcile.go +++ b/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver_reconcile.go @@ -40,11 +40,7 @@ func (s *AzureSqlServerManager) Ensure(ctx context.Context, obj runtime.Object, } // convert kube labels to expected tag format - labels := map[string]*string{} - for k, v := range instance.GetLabels() { - value := v - labels[k] = &value - } + tags, _ := helpers.LabelsToTags(instance.GetLabels()) // set a spec hash if one hasn't been set hash := helpers.Hash256(instance.Spec) @@ -136,7 +132,7 @@ func (s *AzureSqlServerManager) Ensure(ctx context.Context, obj runtime.Object, // create the sql server instance.Status.Provisioning = true - if _, err := s.CreateOrUpdateSQLServer(ctx, instance.Spec.ResourceGroup, instance.Spec.Location, instance.Name, labels, azureSQLServerProperties, false); err != nil { + if _, err := s.CreateOrUpdateSQLServer(ctx, instance.Spec.ResourceGroup, instance.Spec.Location, instance.Name, tags, azureSQLServerProperties, false); err != nil { instance.Status.Message = err.Error() azerr := errhelp.NewAzureErrorAzureError(err) From 4d99340c10be3b15e85c515a4603ff6b17d56bcd Mon Sep 17 00:00:00 2001 From: Erin Corson Date: Fri, 27 Mar 2020 16:53:36 -0600 Subject: [PATCH 2/5] translate bad characters instead of dropping labels when creating tags for Azure --- pkg/helpers/helpers_labels_test.go | 78 +++++++++++++++++++ pkg/helpers/labels.go | 18 +++-- pkg/helpers/stringhelper.go | 8 ++ .../azuresqlserver_reconcile.go | 2 +- 4 files changed, 97 insertions(+), 9 deletions(-) create mode 100644 pkg/helpers/helpers_labels_test.go diff --git a/pkg/helpers/helpers_labels_test.go b/pkg/helpers/helpers_labels_test.go new file mode 100644 index 00000000000..5d94e312890 --- /dev/null +++ b/pkg/helpers/helpers_labels_test.go @@ -0,0 +1,78 @@ +package helpers + +import ( + "log" + "testing" + + "github.com/Azure/go-autorest/autorest/to" +) + +func TestLabelsToTags(t *testing.T) { + checks := []struct { + Name string + In map[string]string + Out map[string]*string + }{ + { + Name: "normal labels", + In: map[string]string{ + "age": "null", + "type": "null", + }, + Out: map[string]*string{ + "age": to.StringPtr("null"), + "type": to.StringPtr("null"), + }, + }, + { + Name: "backslash labels", + In: map[string]string{ + "age/date": "null", + "type\\kind": "null", + "fun/\\zone": "null", + }, + Out: map[string]*string{ + "age.date": to.StringPtr("null"), + "type.kind": to.StringPtr("null"), + "fun..zone": to.StringPtr("null"), + }, + }, + { + Name: "greater than less than labels", + In: map[string]string{ + "age>date": "null", + "typezone": "null", + }, + Out: map[string]*string{ + "age.date": to.StringPtr("null"), + "type.kind": to.StringPtr("null"), + "fun..zone": to.StringPtr("null"), + }, + }, + { + Name: "percent labels", + In: map[string]string{ + "age%date": "null", + "%": "null", + }, + Out: map[string]*string{ + "age.date": to.StringPtr("null"), + ".": to.StringPtr("null"), + }, + }, + } + for _, check := range checks { + log.Println("Checking", check.Name) + translated := LabelsToTags(check.In) + for k, v := range translated { + value := v + if check.Out[k] == nil { + t.Errorf("Expected 'null'\nGot nil\n%q", k) + } + if check.Out[k] != nil && *value != *check.Out[k] { + t.Errorf("Expected %s\nGot %s", *check.Out[k], *value) + } + } + } +} diff --git a/pkg/helpers/labels.go b/pkg/helpers/labels.go index c4e363716f6..001a78de280 100644 --- a/pkg/helpers/labels.go +++ b/pkg/helpers/labels.go @@ -3,20 +3,22 @@ package helpers -import "strings" +import ( + "strings" +) // LabelsToTags converts labels from a kube resource to the data structure expected by Azure for tags -func LabelsToTags(in map[string]string) (map[string]*string, [][]string) { +// this function will translate characters that are not allows by Azure to "."s +func LabelsToTags(in map[string]string) map[string]*string { out := map[string]*string{} - issues := [][]string{} for k, v := range in { + newK := k + value := v if strings.ContainsAny(k, "<>%/?\\") { - issues = append(issues, []string{k, "contains a character not allowed in Azure tags"}) - } else { - value := v - out[k] = &value + newK = ReplaceAny(k, []string{"<", ">", "%", "/", "\\\\"}) } + out[newK] = &value } - return out, issues + return out } diff --git a/pkg/helpers/stringhelper.go b/pkg/helpers/stringhelper.go index 5613f45cb8f..92e8e10105e 100644 --- a/pkg/helpers/stringhelper.go +++ b/pkg/helpers/stringhelper.go @@ -8,6 +8,7 @@ import ( "encoding/json" "fmt" "math/rand" + "regexp" "strings" "time" "unicode" @@ -146,3 +147,10 @@ func Hash256(i interface{}) string { h.Write(inBytes) return fmt.Sprintf("%x", h.Sum(nil)) } + +// ReplaceAny replaces any instance of the strings passes in the chars slice +// replacing a backslash is problematic so it will require 4 eg []string{"\\\\"} +func ReplaceAny(s string, chars []string) string { + reg := regexp.MustCompile(fmt.Sprintf(`(%s)`, strings.Join(chars, "|"))) + return reg.ReplaceAllString(s, ".") +} diff --git a/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver_reconcile.go b/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver_reconcile.go index 8881cac86ff..25972fe2024 100644 --- a/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver_reconcile.go +++ b/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver_reconcile.go @@ -39,7 +39,7 @@ func (s *AzureSqlServerManager) Ensure(ctx context.Context, obj runtime.Object, } // convert kube labels to expected tag format - tags, _ := helpers.LabelsToTags(instance.GetLabels()) + tags := helpers.LabelsToTags(instance.GetLabels()) // set a spec hash if one hasn't been set hash := helpers.Hash256(instance.Spec) From 8d0895ea593f8362074cc8a98fdf1e11ac05e12d Mon Sep 17 00:00:00 2001 From: Erin Corson Date: Mon, 30 Mar 2020 09:59:05 -0600 Subject: [PATCH 3/5] remove extra hash call --- .../azuresql/azuresqlserver/azuresqlserver_reconcile.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver_reconcile.go b/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver_reconcile.go index 25972fe2024..29b080d0e64 100644 --- a/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver_reconcile.go +++ b/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver_reconcile.go @@ -41,13 +41,6 @@ func (s *AzureSqlServerManager) Ensure(ctx context.Context, obj runtime.Object, // convert kube labels to expected tag format tags := helpers.LabelsToTags(instance.GetLabels()) - // set a spec hash if one hasn't been set - hash := helpers.Hash256(instance.Spec) - if instance.Status.SpecHash == hash && instance.Status.Provisioned { - instance.Status.RequestedAt = nil - return true, nil - } - // Check to see if secret already exists for admin username/password // create or update the secret key := types.NamespacedName{Name: instance.Name, Namespace: instance.Namespace} From cbe7ced05881c5403ce61813fe48e2defd6f7499 Mon Sep 17 00:00:00 2001 From: Erin Corson Date: Mon, 30 Mar 2020 12:34:07 -0600 Subject: [PATCH 4/5] adding license header --- pkg/helpers/helpers_labels_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/helpers/helpers_labels_test.go b/pkg/helpers/helpers_labels_test.go index 5d94e312890..2eb634348a5 100644 --- a/pkg/helpers/helpers_labels_test.go +++ b/pkg/helpers/helpers_labels_test.go @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + package helpers import ( From b886009e60ba4b21cd5ee0df3a9dd8c31c0ab45a Mon Sep 17 00:00:00 2001 From: Erin Corson Date: Tue, 31 Mar 2020 17:08:55 -0600 Subject: [PATCH 5/5] filter ? and update sql db --- pkg/helpers/labels.go | 2 +- .../azuresql/azuresqldb/azuresqldb_reconcile.go | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/pkg/helpers/labels.go b/pkg/helpers/labels.go index 001a78de280..7647a895242 100644 --- a/pkg/helpers/labels.go +++ b/pkg/helpers/labels.go @@ -15,7 +15,7 @@ func LabelsToTags(in map[string]string) map[string]*string { newK := k value := v if strings.ContainsAny(k, "<>%/?\\") { - newK = ReplaceAny(k, []string{"<", ">", "%", "/", "\\\\"}) + newK = ReplaceAny(k, []string{"<", ">", "%", "/", "\\\\", "?"}) } out[newK] = &value } diff --git a/pkg/resourcemanager/azuresql/azuresqldb/azuresqldb_reconcile.go b/pkg/resourcemanager/azuresql/azuresqldb/azuresqldb_reconcile.go index fae66455458..70276ecb232 100644 --- a/pkg/resourcemanager/azuresql/azuresqldb/azuresqldb_reconcile.go +++ b/pkg/resourcemanager/azuresql/azuresqldb/azuresqldb_reconcile.go @@ -42,11 +42,7 @@ func (db *AzureSqlDbManager) Ensure(ctx context.Context, obj runtime.Object, opt dbEdition := instance.Spec.Edition // convert kube labels to expected tag format - labels := map[string]*string{} - for k, v := range instance.GetLabels() { - value := v - labels[k] = &value - } + labels := helpers.LabelsToTags(instance.GetLabels()) azureSQLDatabaseProperties := azuresqlshared.SQLDatabaseProperties{ DatabaseName: dbName,