From 197d830472a11ffea8c9b0e4b127da78c43b642a Mon Sep 17 00:00:00 2001 From: Michael Nguyen Date: Fri, 20 Sep 2024 14:11:45 -0400 Subject: [PATCH 1/4] ore aws: add ability to tag images We need the ability to tag images to facilitate garbage collection of RHCOS AMIs that are not used in boot images. The pre-existing tagging functionality on the initial upload cannot be leveraged because we don't know whether a RHCOS build will be used as a boot image at build time. --- mantle/cmd/ore/aws/tag-image.go | 69 +++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 mantle/cmd/ore/aws/tag-image.go diff --git a/mantle/cmd/ore/aws/tag-image.go b/mantle/cmd/ore/aws/tag-image.go new file mode 100644 index 0000000000..c766f1219a --- /dev/null +++ b/mantle/cmd/ore/aws/tag-image.go @@ -0,0 +1,69 @@ +// Copyright 2017 CoreOS, Inc. +// +// 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 aws + +import ( + "fmt" + "os" + "strings" + + "github.com/spf13/cobra" +) + +var ( + cmdTagImage = &cobra.Command{ + Use: "tag-image --ami --tags foo=bar ...", + Short: "Tag an AMI", + Run: runTagImage, + } + tags []string +) + +func init() { + // Initialize the command and its flags + AWS.AddCommand(cmdTagImage) + cmdTagImage.Flags().StringVar(&amiID, "ami", "", "AWS AMI ID") + cmdTagImage.Flags().StringVar(®ion, "region", "", "Region") + cmdTagImage.Flags().StringSliceVar(&tags, "tags", []string{}, "list of key=value tags to attach to the AMI") +} + +func runTagImage(cmd *cobra.Command, args []string) { + if amiID == "" { + fmt.Fprintf(os.Stderr, "Provide --ami to tag\n") + os.Exit(1) + } + + if region == "" { + fmt.Fprintf(os.Stderr, "Provide --region\n") + os.Exit(1) + } + + tagMap := make(map[string]string) + for _, tag := range tags { + splitTag := strings.SplitN(tag, "=", 2) + if len(splitTag) != 2 { + fmt.Fprintf(os.Stderr, "invalid tag format; should be key=value, not %v\n", tag) + os.Exit(1) + } + key, value := splitTag[0], splitTag[1] + tagMap[key] = value + } + + err := API.CreateTags([]string{amiID}, tagMap) + if err != nil { + fmt.Fprintf(os.Stderr, "couldn't create image tags: %v", err) + os.Exit(1) + } +} From 4a0e475a85a9c195959e7ab3f4ac1810267fa02e Mon Sep 17 00:00:00 2001 From: Michael Nguyen Date: Thu, 26 Sep 2024 14:25:17 -0400 Subject: [PATCH 2/4] ore aliyun: add ability to tag images Add ability to tag images to facilate resource management. --- mantle/cmd/ore/aliyun/tag-image.go | 71 ++++++++++++++++++++++++++++++ mantle/platform/api/aliyun/api.go | 26 +++++++++++ 2 files changed, 97 insertions(+) create mode 100644 mantle/cmd/ore/aliyun/tag-image.go diff --git a/mantle/cmd/ore/aliyun/tag-image.go b/mantle/cmd/ore/aliyun/tag-image.go new file mode 100644 index 0000000000..7a1df989ae --- /dev/null +++ b/mantle/cmd/ore/aliyun/tag-image.go @@ -0,0 +1,71 @@ +// Copyright 2017 CoreOS, Inc. +// +// 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 aliyun + +import ( + "fmt" + "os" + "strings" + + "github.com/spf13/cobra" +) + +var ( + cmdTagImage = &cobra.Command{ + Use: "tag-image --id --tags foo=bar ...", + Short: "Tag an image", + Run: runTagImage, + } + id string + tags []string + region string +) + +func init() { + // Initialize the command and its flags + Aliyun.AddCommand(cmdTagImage) + cmdTagImage.Flags().StringVar(&id, "id", "", "Aliyun Image ID") + cmdTagImage.Flags().StringVar(®ion, "region", "", "Region") + cmdTagImage.Flags().StringSliceVar(&tags, "tags", []string{}, "list of key=value tags to attach to the Aliyun image") +} + +func runTagImage(cmd *cobra.Command, args []string) { + if id == "" { + fmt.Fprintf(os.Stderr, "Provide --id to tag\n") + os.Exit(1) + } + + if region == "" { + fmt.Fprintf(os.Stderr, "Provide --region\n") + os.Exit(1) + } + + tagMap := make(map[string]string) + for _, tag := range tags { + splitTag := strings.SplitN(tag, "=", 2) + if len(splitTag) != 2 { + fmt.Fprintf(os.Stderr, "invalid tag format; should be key=value, not %v\n", tag) + os.Exit(1) + } + key, value := splitTag[0], splitTag[1] + tagMap[key] = value + } + + err := API.CreateTags(id, tagMap, region) + if err != nil { + fmt.Fprintf(os.Stderr, "couldn't create image tags: %v", err) + os.Exit(1) + } +} diff --git a/mantle/platform/api/aliyun/api.go b/mantle/platform/api/aliyun/api.go index bb5a9ad907..473c75a527 100644 --- a/mantle/platform/api/aliyun/api.go +++ b/mantle/platform/api/aliyun/api.go @@ -370,6 +370,32 @@ func (a *API) DeleteImage(id string, force bool) error { return errs.AsError() } +func (a *API) CreateTags(resource string, tags map[string]string, region string) error { + request := ecs.CreateAddTagsRequest() + request.SetConnectTimeout(defaultConnectTimeout) + request.SetReadTimeout(defaultReadTimeout) + request.ResourceId = resource + request.RegionId = region + request.ResourceType = "image" + + tagObjs := make([]ecs.AddTagsTag, 0, len(tags)) + for key, value := range tags { + tagObjs = append(tagObjs, ecs.AddTagsTag{ + Key: key, + Value: value, + }) + } + + request.Tag = &tagObjs + response, err := a.ecs.AddTags(request) + plog.Infof("response %v", response) + if err != nil { + return fmt.Errorf("unable to add tags: %v", err) + } + + return err +} + // DeleteSnapshot deletes a snapshot func (a *API) DeleteSnapshot(id string, force bool) error { request := ecs.CreateDeleteSnapshotRequest() From 4b098a9b6a685efc5f9de3f181b80f837cd8ca01 Mon Sep 17 00:00:00 2001 From: Michael Nguyen Date: Wed, 9 Oct 2024 10:05:56 -0400 Subject: [PATCH 3/4] ore gcloud: add ability to label images Add ability to label images to facilate resource management. --- mantle/cmd/ore/gcloud/label-image.go | 69 ++++++++++++++++++++++++++++ mantle/platform/api/gcloud/image.go | 21 +++++++++ 2 files changed, 90 insertions(+) create mode 100644 mantle/cmd/ore/gcloud/label-image.go diff --git a/mantle/cmd/ore/gcloud/label-image.go b/mantle/cmd/ore/gcloud/label-image.go new file mode 100644 index 0000000000..7d47df51f8 --- /dev/null +++ b/mantle/cmd/ore/gcloud/label-image.go @@ -0,0 +1,69 @@ +// Copyright 2017 CoreOS, Inc. +// +// 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 gcloud + +import ( + "fmt" + "os" + "strings" + + "github.com/spf13/cobra" +) + +var ( + cmdLabelImage = &cobra.Command{ + Use: "label-image --name --labels foo=bar ...", + Short: "label an image", + Run: runLabelImage, + } + name string + labels []string +) + +func init() { + // Initialize the command and its flags + GCloud.AddCommand(cmdLabelImage) + cmdLabelImage.Flags().StringVar(&name, "name", "", "GCloud Image Name") + cmdLabelImage.Flags().StringSliceVar(&labels, "labels", []string{}, "list of key=value labels to attach to the GCloud image") +} + +func runLabelImage(cmd *cobra.Command, args []string) { + if name == "" { + fmt.Fprintf(os.Stderr, "Provide --name to label\n") + os.Exit(1) + } + + if len(labels) < 1 { + fmt.Fprintf(os.Stderr, "Provide at least one --label to label\n") + os.Exit(1) + } + + labelMap := make(map[string]string) + for _, label := range labels { + splitLabel := strings.SplitN(label, "=", 2) + if len(splitLabel) != 2 { + fmt.Fprintf(os.Stderr, "invalid label format; should be key=value, not %v\n", label) + os.Exit(1) + } + key, value := splitLabel[0], splitLabel[1] + labelMap[key] = value + } + + err := api.SetImageLabels(name, labelMap) + if err != nil { + fmt.Fprintf(os.Stderr, "couldn't create image labels: %v", err) + os.Exit(1) + } +} diff --git a/mantle/platform/api/gcloud/image.go b/mantle/platform/api/gcloud/image.go index aac05654b1..0ab244a89a 100644 --- a/mantle/platform/api/gcloud/image.go +++ b/mantle/platform/api/gcloud/image.go @@ -283,3 +283,24 @@ func (a *API) SetImagePublic(name string) error { } return nil } + +// Add label(s) to an image +func (a *API) SetImageLabels(name string, labels map[string]string) error { + img, err := a.compute.Images.Get(a.options.Project, name).Do() + if err != nil { + return fmt.Errorf("Getting image %s failed: %v", name, err) + } + + req := &compute.GlobalSetLabelsRequest{ + LabelFingerprint: img.LabelFingerprint, + Labels: labels, + } + + op, err := a.compute.Images.SetLabels(a.options.Project, name, req).Do() + if err != nil { + return fmt.Errorf("Adding labels to %s failed: %v", name, err) + } + + plog.Infof("Updated labels on image %s: %v", name, op.Status) + return nil +} From e4a100488fbc2fff78f91c2b9df5740d5da83753 Mon Sep 17 00:00:00 2001 From: Michael Nguyen Date: Tue, 29 Oct 2024 08:25:15 -0400 Subject: [PATCH 4/4] ore azure: add ability to tag images Add ability to tag images to facilate resource management. --- mantle/cmd/ore/azure/tag-blob.go | 98 ++++++++++++++++++++++++++++ mantle/platform/api/azure/storage.go | 10 +++ 2 files changed, 108 insertions(+) create mode 100644 mantle/cmd/ore/azure/tag-blob.go diff --git a/mantle/cmd/ore/azure/tag-blob.go b/mantle/cmd/ore/azure/tag-blob.go new file mode 100644 index 0000000000..6bd2bf0b6f --- /dev/null +++ b/mantle/cmd/ore/azure/tag-blob.go @@ -0,0 +1,98 @@ +// Copyright 2022 Red Hat +// +// 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 azure + +import ( + "fmt" + "os" + "strings" + + "github.com/spf13/cobra" +) + +var ( + cmdTagBlob = &cobra.Command{ + Use: "tag-blob", + Short: "Tag a Azure storage blob", + Long: "tag a storage blob on Azure.", + Run: runSetMetadata, + } + + bmo struct { + tags []string + storageacct string + container string + blob string + resourceGroup string + } +) + +func init() { + sv := cmdTagBlob.Flags().StringVar + ssv := cmdTagBlob.Flags().StringSliceVar + sv(&bmo.storageacct, "storage-account", "kola", "storage account name") + sv(&bmo.container, "container", "vhds", "container name") + sv(&bmo.blob, "blob-name", "", "name of the blob") + sv(&bmo.resourceGroup, "resource-group", "kola", "resource group name") + ssv(&bmo.tags, "tags", []string{}, "list of key=value tags to attach to the Azure storage blob") + Azure.AddCommand(cmdTagBlob) +} + +func runSetMetadata(cmd *cobra.Command, args []string) { + if bmo.blob == "" { + fmt.Fprintf(os.Stderr, "Provide --blob-name to tag\n") + os.Exit(1) + } + + if len(bmo.tags) < 1 { + fmt.Fprintf(os.Stderr, "Provide --tag to tag\n") + os.Exit(1) + } + + if err := api.SetupClients(); err != nil { + fmt.Fprintf(os.Stderr, "setting up clients: %v\n", err) + os.Exit(1) + } + + kr, err := api.GetStorageServiceKeys(bmo.storageacct, bmo.resourceGroup) + if err != nil { + fmt.Fprintf(os.Stderr, "Fetching storage service keys failed: %v\n", err) + os.Exit(1) + } + + if len(kr.Keys) == 0 { + fmt.Fprintf(os.Stderr, "No storage service keys found") + os.Exit(1) + } + k := kr.Keys + key := k[0].Value + + tagMap := make(map[string]*string) + for _, tag := range bmo.tags { + splitTag := strings.SplitN(tag, "=", 2) + if len(splitTag) != 2 { + fmt.Fprintf(os.Stderr, "invalid tag format; should be key=value, not %v\n", tag) + os.Exit(1) + } + key, value := splitTag[0], splitTag[1] + tagMap[key] = &value + } + + err = api.SetBlobMetadata(bmo.storageacct, *key, bmo.container, bmo.blob, tagMap) + if err != nil { + fmt.Fprintf(os.Stderr, "couldn't create image tags: %v", err) + os.Exit(1) + } +} diff --git a/mantle/platform/api/azure/storage.go b/mantle/platform/api/azure/storage.go index 2e6336b855..c5094a11d8 100644 --- a/mantle/platform/api/azure/storage.go +++ b/mantle/platform/api/azure/storage.go @@ -174,6 +174,16 @@ func (a *API) DeleteBlockBlob(storageaccount, key, container, blob string) error return err } +func (a *API) SetBlobMetadata(storageaccount, key, container, blobname string, tags map[string]*string) error { + client, err := getPageBlobClient(storageaccount, key, container, blobname) + if err != nil { + return err + } + + _, err = client.SetMetadata(context.Background(), tags, nil) + return err +} + func getBlockBlobClient(storageaccount, key string) (*azblob.Client, error) { serviceURL := fmt.Sprintf("https://%s.blob.core.windows.net/", storageaccount) cred, err := azblob.NewSharedKeyCredential(storageaccount, key)