From 62a461136332b72c09da0f4f678774393ccbdfdf Mon Sep 17 00:00:00 2001 From: ioito Date: Fri, 8 Apr 2022 16:23:43 +0800 Subject: [PATCH] fix(region): google label encode --- pkg/multicloud/google/instance.go | 18 ++++--- pkg/multicloud/tag_base.go | 7 ++- pkg/util/encode/doc.go | 1 + pkg/util/encode/encode.go | 81 +++++++++++++++++++++++++++++++ pkg/util/encode/encode_test.go | 57 ++++++++++++++++++++++ 5 files changed, 155 insertions(+), 9 deletions(-) create mode 100644 pkg/util/encode/doc.go create mode 100644 pkg/util/encode/encode.go create mode 100644 pkg/util/encode/encode_test.go diff --git a/pkg/multicloud/google/instance.go b/pkg/multicloud/google/instance.go index f0017e3b51..60227b8c9c 100644 --- a/pkg/multicloud/google/instance.go +++ b/pkg/multicloud/google/instance.go @@ -32,6 +32,7 @@ import ( "yunion.io/x/onecloud/pkg/multicloud" "yunion.io/x/onecloud/pkg/util/billing" "yunion.io/x/onecloud/pkg/util/cloudinit" + "yunion.io/x/onecloud/pkg/util/encode" "yunion.io/x/onecloud/pkg/util/imagetools" "yunion.io/x/onecloud/pkg/util/pinyinutils" ) @@ -684,7 +685,7 @@ func (region *SRegion) _createVM(zone string, desc *cloudprovider.SManagedVMCrea labels := map[string]string{} for k, v := range desc.Tags { - labels[strings.ToLower(k)] = v + labels[encode.EncodeGoogleLabel(k)] = encode.EncodeGoogleLabel(v) } if len(labels) > 0 { @@ -936,7 +937,11 @@ func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudpro return nil, errors.Wrapf(cloudprovider.ErrNotFound, "no valid system disk found") } -func (region *SRegion) SetLabels(id string, labels map[string]string, labelFingerprint string) error { +func (region *SRegion) SetLabels(id string, _labels map[string]string, labelFingerprint string) error { + labels := map[string]string{} + for k, v := range _labels { + labels[encode.EncodeGoogleLabel(k)] = encode.EncodeGoogleLabel(v) + } params := map[string]interface{}{ "labels": labels, "labelFingerprint": labelFingerprint, @@ -948,13 +953,10 @@ func (region *SRegion) SetLabels(id string, labels map[string]string, labelFinge return nil } -func (self *SInstance) SetTags(_tags map[string]string, replace bool) error { - tags := map[string]string{} - for k, v := range _tags { - tags[strings.ToLower(k)] = v - } +func (self *SInstance) SetTags(tags map[string]string, replace bool) error { if !replace { - for k, v := range self.Labels { + oldTags, _ := self.GetTags() + for k, v := range oldTags { if _, ok := tags[k]; !ok { tags[k] = v } diff --git a/pkg/multicloud/tag_base.go b/pkg/multicloud/tag_base.go index c3ba0a879c..020fcc8219 100644 --- a/pkg/multicloud/tag_base.go +++ b/pkg/multicloud/tag_base.go @@ -21,6 +21,7 @@ import ( "yunion.io/x/onecloud/pkg/apis" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/util/encode" ) type STagBase struct { @@ -201,7 +202,11 @@ type GoogleTags struct { } func (self *GoogleTags) GetTags() (map[string]string, error) { - return self.Labels, nil + ret := map[string]string{} + for k, v := range self.Labels { + ret[encode.DecodeGoogleLable(k)] = encode.DecodeGoogleLable(v) + } + return ret, nil } func (self *GoogleTags) GetSysTags() map[string]string { diff --git a/pkg/util/encode/doc.go b/pkg/util/encode/doc.go new file mode 100644 index 0000000000..f1ec9d2502 --- /dev/null +++ b/pkg/util/encode/doc.go @@ -0,0 +1 @@ +package encode // import "yunion.io/x/onecloud/pkg/util/encode" diff --git a/pkg/util/encode/encode.go b/pkg/util/encode/encode.go new file mode 100644 index 0000000000..1420309784 --- /dev/null +++ b/pkg/util/encode/encode.go @@ -0,0 +1,81 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package encode + +import ( + "strings" +) + +const lowerhex = "0123456789abcdef" + +func ishex(c rune) bool { + switch { + case rune('0') <= c && c <= rune('9'): + return true + case rune('a') <= c && c <= rune('f'): + return true + } + return false +} + +func unhex(c rune) byte { + switch { + case rune('0') <= c && c <= rune('9'): + return byte(c) - '0' + case rune('a') <= c && c <= rune('f'): + return byte(c) - 'a' + 10 + } + return 0 +} + +func shouldEncode(c rune) bool { + if (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c > 256 { + return false + } + return true +} + +func EncodeGoogleLabel(label string) string { + var t strings.Builder + for _, c := range label { + if shouldEncode(c) { + t.WriteByte('_') + t.WriteByte(lowerhex[c>>4]) + t.WriteByte(lowerhex[c&15]) + continue + } + t.WriteRune(c) + } + return t.String() +} + +func DecodeGoogleLable(label string) string { + s := []rune{} + for _, c := range label { + s = append(s, c) + } + var t strings.Builder + for j := 0; j < len(s); { + c := s[j] + if c == rune('_') && j+2 <= len(s) && ishex(s[j+1]) && ishex(s[j+2]) { + t.WriteByte(unhex(s[j+1])<<4 | unhex(s[j+2])) + j += 3 + } else { + t.WriteRune(s[j]) + j += 1 + } + } + return t.String() +} diff --git a/pkg/util/encode/encode_test.go b/pkg/util/encode/encode_test.go new file mode 100644 index 0000000000..80ab9b5729 --- /dev/null +++ b/pkg/util/encode/encode_test.go @@ -0,0 +1,57 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package encode + +import ( + "testing" +) + +func TestLabelEncode(t *testing.T) { + cases := []struct { + label string + encodeLabel string + }{ + { + label: "app/test/hellow", + encodeLabel: "app_2ftest_2fhellow", + }, + { + label: "app/test_hellow", + encodeLabel: "app_2ftest_5fhellow", + }, + { + label: "projName", + encodeLabel: "proj_4eame", + }, + { + label: "你好test", + encodeLabel: "你好test", + }, + { + label: "你好test:", + encodeLabel: "你好test_3a", + }, + } + for _, label := range cases { + encodeLabel := EncodeGoogleLabel(label.label) + if label.encodeLabel != encodeLabel { + t.Fatalf("encode %s to %s want: %s", label.label, encodeLabel, label.encodeLabel) + } + decodeLabel := DecodeGoogleLable(encodeLabel) + if label.label != decodeLabel { + t.Fatalf("decode %s to %s want: %s", encodeLabel, decodeLabel, label.label) + } + } +}