Skip to content

Commit c0eb2c2

Browse files
committed
feat: support adding ResourceManagerTags to compute instances
Signed-off-by: Carlos Salas <[email protected]>
1 parent eb65f59 commit c0eb2c2

22 files changed

+500
-5
lines changed

api/v1alpha3/zz_generated.conversion.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v1alpha4/gcpcluster_conversion.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ func (src *GCPCluster) ConvertTo(dstRaw conversion.Hub) error { // nolint
5252
dst.Spec.CredentialsRef = restored.Spec.CredentialsRef.DeepCopy()
5353
}
5454

55+
for _, restoredTag := range restored.Spec.ResourceManagerTags {
56+
dst.Spec.ResourceManagerTags = append(dst.Spec.ResourceManagerTags, *restoredTag.DeepCopy())
57+
}
58+
5559
return nil
5660
}
5761

api/v1alpha4/gcpclustertemplate_conversion.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ func (src *GCPClusterTemplate) ConvertTo(dstRaw conversion.Hub) error { // nolin
5454
dst.Spec.Template.Spec.CredentialsRef = restored.Spec.Template.Spec.CredentialsRef.DeepCopy()
5555
}
5656

57+
for _, restoredTag := range restored.Spec.Template.Spec.ResourceManagerTags {
58+
dst.Spec.Template.Spec.ResourceManagerTags = append(dst.Spec.Template.Spec.ResourceManagerTags, *restoredTag.DeepCopy())
59+
}
60+
5761
return nil
5862
}
5963

api/v1alpha4/gcpmachine_conversion.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ func (src *GCPMachine) ConvertTo(dstRaw conversion.Hub) error { // nolint
5353
dst.Spec.ConfidentialCompute = restored.Spec.ConfidentialCompute
5454
}
5555

56+
if restored.Spec.ResourceManagerTags != nil {
57+
dst.Spec.ResourceManagerTags = restored.Spec.ResourceManagerTags
58+
}
59+
5660
return nil
5761
}
5862

api/v1alpha4/gcpmachinetemplate_conversion.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ func (src *GCPMachineTemplate) ConvertTo(dstRaw conversion.Hub) error { // nolin
5454
dst.Spec.Template.Spec.ConfidentialCompute = restored.Spec.Template.Spec.ConfidentialCompute
5555
}
5656

57+
if restored.Spec.Template.Spec.ResourceManagerTags != nil {
58+
dst.Spec.Template.Spec.ResourceManagerTags = restored.Spec.Template.Spec.ResourceManagerTags
59+
}
60+
5761
return nil
5862
}
5963

api/v1alpha4/zz_generated.conversion.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v1beta1/gcpcluster_types.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ type GCPClusterSpec struct {
5454
// +optional
5555
AdditionalLabels Labels `json:"additionalLabels,omitempty"`
5656

57+
// ResourceManagerTags is an optional set of tags to apply to GCP resources managed
58+
// by the GCP provider. GCP supports a maximum of 50 tags per resource.
59+
// +kubebuilder:validation:MaxItems=50
60+
// +listType=map
61+
// +listMapKey=key
62+
// +optional
63+
ResourceManagerTags []ResourceManagerTag `json:"resourceManagerTags,omitempty"`
64+
5765
// CredentialsRef is a reference to a Secret that contains the credentials to use for provisioning this cluster. If not
5866
// supplied then the credentials of the controller will be used.
5967
// +optional

api/v1beta1/gcpmachine_types.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,14 @@ type GCPMachineSpec struct {
197197
// +optional
198198
AdditionalNetworkTags []string `json:"additionalNetworkTags,omitempty"`
199199

200+
// ResourceManagerTags is an optional set of tags to apply to GCP resources managed
201+
// by the GCP provider. GCP supports a maximum of 50 tags per resource.
202+
// +kubebuilder:validation:MaxItems=50
203+
// +listType=map
204+
// +listMapKey=key
205+
// +optional
206+
ResourceManagerTags []ResourceManagerTag `json:"resourceManagerTags,omitempty"`
207+
200208
// RootDeviceSize is the size of the root volume in GB.
201209
// Defaults to 30.
202210
// +optional

api/v1beta1/tags.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1beta1
18+
19+
import (
20+
"context"
21+
"fmt"
22+
23+
resourcemanager "cloud.google.com/go/resourcemanager/apiv3"
24+
rmpb "cloud.google.com/go/resourcemanager/apiv3/resourcemanagerpb"
25+
"sigs.k8s.io/controller-runtime/pkg/log"
26+
)
27+
28+
// ResourceManagerTagsMap defines a map of key value pairs as expected by compute.InstanceParams.ResourceManagerTags.
29+
type ResourceManagerTagsMap map[string]string
30+
31+
// ResourceManagerTag is a tag to apply to GCP resources managed by the GCP provider.
32+
type ResourceManagerTag struct {
33+
// ParentID is the ID of the hierarchical resource where the tags are defined
34+
// e.g. at the Organization or the Project level. To find the Organization or Project ID ref
35+
// https://cloud.google.com/resource-manager/docs/creating-managing-organization#retrieving_your_organization_id
36+
// https://cloud.google.com/resource-manager/docs/creating-managing-projects#identifying_projects
37+
// An OrganizationID must consist of decimal numbers, and cannot have leading zeroes.
38+
// A ProjectID must be 6 to 30 characters in length, can only contain lowercase letters,
39+
// numbers, and hyphens, and must start with a letter, and cannot end with a hyphen.
40+
// +kubebuilder:validation:Required
41+
// +kubebuilder:validation:MinLength=1
42+
// +kubebuilder:validation:MaxLength=32
43+
// +kubebuilder:validation:Pattern=`(^[1-9][0-9]{0,31}$)|(^[a-z][a-z0-9-]{4,28}[a-z0-9]$)`
44+
ParentID string `json:"parentID"`
45+
46+
// Key is the key part of the tag. A tag key can have a maximum of 63 characters and cannot
47+
// be empty. Tag key must begin and end with an alphanumeric character, and must contain
48+
// only uppercase, lowercase alphanumeric characters, and the following special
49+
// characters `._-`.
50+
// +kubebuilder:validation:Required
51+
// +kubebuilder:validation:MinLength=1
52+
// +kubebuilder:validation:MaxLength=63
53+
// +kubebuilder:validation:Pattern=`^[a-zA-Z0-9]([0-9A-Za-z_.-]{0,61}[a-zA-Z0-9])?$`
54+
Key string `json:"key"`
55+
56+
// Value is the value part of the tag. A tag value can have a maximum of 63 characters and
57+
// cannot be empty. Tag value must begin and end with an alphanumeric character, and must
58+
// contain only uppercase, lowercase alphanumeric characters, and the following special
59+
// characters `_-.@%=+:,*#&(){}[]` and spaces.
60+
// +kubebuilder:validation:Required
61+
// +kubebuilder:validation:MinLength=1
62+
// +kubebuilder:validation:MaxLength=63
63+
// +kubebuilder:validation:Pattern=`^[a-zA-Z0-9]([0-9A-Za-z_.@%=+:,*#&()\[\]{}\-\s]{0,61}[a-zA-Z0-9])?$`
64+
Value string `json:"value"`
65+
}
66+
67+
// AddResourceManagerTags binds the passed resource-manager tags to the resource. Tag keys and Tag Values
68+
// will be created by the user and only the Tag bindings to the Compute Instance will be created.
69+
// If the Tag Key/Tag Value cannot be retrieved or no tags are provided, this will be empty and no tags will be added.
70+
func AddResourceManagerTags(ctx context.Context, tagList []ResourceManagerTag) ResourceManagerTagsMap {
71+
tagValueList := make(ResourceManagerTagsMap, len(tagList))
72+
log := log.FromContext(ctx)
73+
if len(tagList) == 0 {
74+
return tagValueList
75+
}
76+
77+
client, err := resourcemanager.NewTagValuesClient(ctx)
78+
if err != nil {
79+
log.Error(err, "failed to create tag values client")
80+
return tagValueList
81+
}
82+
83+
getTagValuesReq := &rmpb.GetNamespacedTagValueRequest{}
84+
for _, tag := range tagList {
85+
getTagValuesReq.Name = fmt.Sprintf("%s/%s/%s", tag.ParentID, tag.Key, tag.Value)
86+
value, err := client.GetNamespacedTagValue(ctx, getTagValuesReq)
87+
if err != nil {
88+
log.Error(err, "failed to retrieve tag value")
89+
return tagValueList
90+
}
91+
tagValueList[value.Parent] = value.Name
92+
}
93+
94+
return tagValueList
95+
}

api/v1beta1/zz_generated.deepcopy.go

Lines changed: 46 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)