diff --git a/README.md b/README.md index 5c89253..e56a1d1 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,12 @@ ## General -The image cleanup client is used to clean up Docker images in a Docker Registry when they are tagged using git SHA. The cleaning is done either using git commit hashes or tags. Defaults to hashes otherwise ```-t``` flag should be used. +The image cleanup client is used to clean up Docker images in a Docker Registry when they are tagged using git SHA. The cleaning is done either using git commit hashes or tags. Defaults to hashes otherwise ```-t``` flag should be used. The tool also allows to clean orphan image stream tags using ```-o``` flag, the orphan image stream tags are images that do not have any Git commit/tag. There are secondary flags which help to norrow the cleaning process such as: +* ```-i``` regex flag that is used to norrow the orphans to be deleted, works exclusively with ```-o``` flag +* ```l``` limit the number of Git commits/tags to be fetched from Git repository, prohibited with ```-o``` flag +* ```-k``` keeps most current n images +* ```--older-than``` considers images that are older than the last update date. +* ```--sort``` sorts the Git Tags, works exclusively with the ```-t``` flag This helps to save space because obsolete images are being removed from the registry. diff --git a/cmd/imagestream.go b/cmd/imagestream.go index 11d24ad..bf1484e 100644 --- a/cmd/imagestream.go +++ b/cmd/imagestream.go @@ -2,12 +2,15 @@ package cmd import ( log "github.com/sirupsen/logrus" + "time" + "regexp" "github.com/appuio/image-cleanup/pkg/cleanup" "github.com/appuio/image-cleanup/pkg/git" "github.com/appuio/image-cleanup/pkg/kubernetes" "github.com/appuio/image-cleanup/pkg/openshift" "github.com/spf13/cobra" + "github.com/karrick/tparse" ) // ImageStreamCleanupOptions is a struct to support the cleanup command @@ -20,6 +23,9 @@ type ImageStreamCleanupOptions struct { Namespace string Tag bool Sorted string + Orphan bool + Duration string + Regex string } // NewImageStreamCleanupCommand creates a cobra command to clean up an imagestream based on commits @@ -33,12 +39,15 @@ func NewImageStreamCleanupCommand() *cobra.Command { Run: o.cleanupImageStreamTags, } cmd.Flags().BoolVarP(&o.Force, "force", "f", false, "delete image stream tags") - cmd.Flags().IntVarP(&o.CommitLimit, "git-commit-limit", "l", 100, "only look at the first commits to compare with tags or use -1 for all commits") + cmd.Flags().IntVarP(&o.CommitLimit, "git-commit-limit", "l", 0, "only look at the first commits to compare with tags or use 0 for all commits") cmd.Flags().StringVarP(&o.RepoPath, "git-repo-path", "p", ".", "absolute path to Git repository (for current dir use: $PWD)") cmd.Flags().StringVarP(&o.Namespace, "namespace", "n", "", "Kubernetes namespace") cmd.Flags().IntVarP(&o.Keep, "keep", "k", 10, "keep most current images") cmd.Flags().BoolVarP(&o.Tag, "tag", "t", false, "use tags instead of commit hashes") cmd.Flags().StringVar(&o.Sorted, "sort", string(git.SortOptionVersion), "sort tags by criteria. Allowed values: [version, alphabetical]") + cmd.Flags().BoolVarP(&o.Orphan, "orphan", "o", false, "delete images that does not match any git commit") + cmd.Flags().StringVar(&o.Duration, "older-than", "", "delete images that are older than the duration. Ex.: [1y2mo3w4d5h6m7s]") + cmd.Flags().StringVarP(&o.Regex, "include", "i", "^[a-z0-9]{40}$", "delete images that match the regex, works only with the -o flag, defaults to matching Git SHA commits") return cmd } @@ -47,8 +56,36 @@ func (o *ImageStreamCleanupOptions) cleanupImageStreamTags(cmd *cobra.Command, a o.ImageStream = args[0] } + if o.Orphan == false && o.Regex != "^[a-z0-9]{40}$" { + log.WithFields(log.Fields{"Orphan": o.Orphan, "Regex": o.Regex}). + Fatal("Missing Orphan flag") + } + + regexp, err := regexp.Compile(o.Regex) + if err != nil { + log.WithField("regex", o.Regex).Fatal("Invalid regex.") + } + if o.Tag && !git.IsValidSortValue(o.Sorted) { - log.WithField("sort_criteria", o.Sorted).Fatal("Invalid sort criteria") + log.WithField("sort_criteria", o.Sorted).Fatal("Invalid sort criteria.") + } + + if o.CommitLimit !=0 && o.Orphan == true { + log.WithFields(log.Fields{"CommitLimit": o.CommitLimit, "Orphan": o.Orphan}). + Fatal("Mutually exclusive flags") + } + + var duration time.Time + if len(o.Duration) > 0 { + var err error + duration, err = tparse.ParseNow(time.RFC3339, "now-" + o.Duration) + if err != nil { + log.WithError(err). + WithField("duration", o.Duration). + Fatal("Could not parse duration.") + } + } else { + duration = time.Now() } if len(o.Namespace) == 0 { @@ -96,7 +133,7 @@ func (o *ImageStreamCleanupOptions) cleanupImageStreamTags(cmd *cobra.Command, a } } - imageStreamTags, err := openshift.GetImageStreamTags(o.Namespace, o.ImageStream) + imageStreamObjectTags, err := openshift.GetImageStreamTags(o.Namespace, o.ImageStream) if err != nil { log.WithError(err). WithFields(log.Fields{ @@ -105,12 +142,20 @@ func (o *ImageStreamCleanupOptions) cleanupImageStreamTags(cmd *cobra.Command, a Fatal("Could not retrieve image stream.") } + imageStreamTags := cleanup.TagsOlderThan(&imageStreamObjectTags, duration) + var matchOption cleanup.MatchOption if o.Tag { matchOption = cleanup.MatchOptionExact } - matchingTags := cleanup.GetMatchingTags(&matchValues, &imageStreamTags, matchOption) + var matchingTags []string + if o.Orphan { + matchingTags = cleanup.GetOrphanTags(&matchValues, &imageStreamTags, matchOption) + matchingTags = cleanup.FilterByRegex(&imageStreamTags, regexp) + } else { + matchingTags = cleanup.GetMatchingTags(&matchValues, &imageStreamTags, matchOption) + } activeImageStreamTags, err := openshift.GetActiveImageStreamTags(o.Namespace, o.ImageStream, imageStreamTags) if err != nil { diff --git a/go.mod b/go.mod index 2c85cda..9729c8f 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,8 @@ require ( github.com/heroku/docker-registry-client v0.0.0-20190909225348-afc9e1acc3d5 github.com/imdario/mergo v0.3.8 // indirect github.com/json-iterator/go v1.1.8 // indirect - github.com/openshift/api v3.9.1-0.20190322043348-8741ff068a47+incompatible // indirect + github.com/karrick/tparse v2.4.2+incompatible + github.com/openshift/api v3.9.1-0.20190322043348-8741ff068a47+incompatible github.com/openshift/client-go v0.0.0-20180830153425-431ec9a26e50 github.com/sirupsen/logrus v1.4.2 github.com/spf13/cobra v0.0.5 diff --git a/go.sum b/go.sum index 26090be..9ca3219 100644 --- a/go.sum +++ b/go.sum @@ -101,6 +101,8 @@ github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGAR github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/karrick/tparse v2.4.2+incompatible h1:+cW306qKAzrASC5XieHkgN7/vPaGKIuK62Q7nI7DIRc= +github.com/karrick/tparse v2.4.2+incompatible/go.mod h1:ASPA+vrIcN1uEW6BZg8vfWbzm69ODPSYZPU6qJyfdK0= github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/gotool v0.0.0-20161130080628-0de1eaf82fa3/go.mod h1:jxZFDH7ILpTPQTk+E2s+z4CUas9lVNjIuKR4c5/zKgM= @@ -146,6 +148,7 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/openshift/api v3.9.0+incompatible h1:fJ/KsefYuZAjmrr3+5U9yZIZbTOpVkDDLDLFresAeYs= github.com/openshift/api v3.9.1-0.20190322043348-8741ff068a47+incompatible h1:p0ypM7AY7k2VY6ILDPbg3LajGA97hFUt2DGVEQz2Yd4= github.com/openshift/api v3.9.1-0.20190322043348-8741ff068a47+incompatible/go.mod h1:dh9o4Fs58gpFXGSYfnVxGR9PnV53I8TW84pQaJDdGiY= github.com/openshift/client-go v0.0.0-20180830153425-431ec9a26e50 h1:y59/+XbTbwzEdS2wveRQTZvjkar7sbVjTNnqFBufr74= diff --git a/pkg/cleanup/cleanup.go b/pkg/cleanup/cleanup.go index a10f28b..e2ca602 100644 --- a/pkg/cleanup/cleanup.go +++ b/pkg/cleanup/cleanup.go @@ -2,8 +2,11 @@ package cleanup import ( "strings" + "regexp" + "time" log "github.com/sirupsen/logrus" + imagev1 "github.com/openshift/api/image/v1" ) // MatchOption type defines how the tags should be matched @@ -62,6 +65,40 @@ func GetInactiveTags(activeTags, tags *[]string) []string { return inactiveTags } +// GetOrphanTags returns the tags that does not have any git commit match +func GetOrphanTags(values, tags *[]string, matchOption MatchOption) []string { + var orphans []string + + log.WithField("values", values).Debug("values") + log.WithField("tags", tags).Debug("tags") + + for _, tag := range *tags { + orphans = append(orphans, tag) + for _, value := range *values { + if match(tag, value, matchOption) { + orphans = orphans[:len(orphans)-1] + break + } + } + } + + return orphans +} + +// FilterByRegex returns the tags that match the regexp +func FilterByRegex(tags *[]string, regexp *regexp.Regexp) []string { + var matchedTags []string + + log.WithField("tags", tags).Debug("tags") + + for _, tag := range *tags { + if regexp.MatchString(tag) { + matchedTags = append(matchedTags, tag) + } + } + return matchedTags +} + // LimitTags returns the tags which should not be kept by removing the first n tags func LimitTags(tags *[]string, keep int) []string { if len(*tags) > keep { @@ -73,6 +110,26 @@ func LimitTags(tags *[]string, keep int) []string { return []string{} } +// TagsOlderThan returns the tags which are older than the specified time +func TagsOlderThan(imageStreamObjectTags *[]imagev1.NamedTagEventList, olderThan time.Time) []string { + var imageStreamTags []string + + for _, imageStreamTag := range *imageStreamObjectTags { + lastUpdatedDate := imageStreamTag.Items[0].Created.Time + for _, tagEvent := range imageStreamTag.Items { + if lastUpdatedDate.Before(tagEvent.Created.Time) { + lastUpdatedDate = tagEvent.Created.Time + } + } + + if lastUpdatedDate.Before(olderThan) { + imageStreamTags = append(imageStreamTags, imageStreamTag.Tag) + } + } + + return imageStreamTags +} + func match(tag, value string, matchOption MatchOption) bool { switch matchOption { case MatchOptionDefault, MatchOptionPrefix: diff --git a/pkg/cleanup/cleanup_test.go b/pkg/cleanup/cleanup_test.go index 6b766a1..b585f69 100644 --- a/pkg/cleanup/cleanup_test.go +++ b/pkg/cleanup/cleanup_test.go @@ -1,9 +1,13 @@ package cleanup import ( + "regexp" "testing" + "time" + imagev1 "github.com/openshift/api/image/v1" "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) type GetMatchingTagsTestCase struct { @@ -11,6 +15,11 @@ type GetMatchingTagsTestCase struct { matchOption MatchOption } +type GetOrphanTagsTestCase struct { + matchValues, tags, expected []string + matchOption MatchOption +} + type GetInactiveTagsTestCase struct { tags, activeTags, expected []string } @@ -20,6 +29,17 @@ type LimitTagsTestCase struct { limit int } +type FilterByRegexTestCase struct { + tags, expected []string +} + +type TagsOlderThanTestCase struct { + tags []imagev1.NamedTagEventList + expected []string + olderThan time.Time + +} + func Test_GetMatchingTags(t *testing.T) { testcases := []GetMatchingTagsTestCase{ GetMatchingTagsTestCase{ @@ -46,13 +66,83 @@ func Test_GetMatchingTags(t *testing.T) { "c8a693ad89e7069674eda512c553ff56d3ca2ffd-debug", }, }, - GetMatchingTagsTestCase{ + } + + for _, testcase := range testcases { + assert.Equal(t, testcase.expected, GetMatchingTags(&testcase.matchValues, &testcase.tags, testcase.matchOption)) + } +} + +func Test_GetOrphanTags(t *testing.T) { + testcases := []GetOrphanTagsTestCase{ + GetOrphanTagsTestCase{ + matchValues: []string{}, + tags: []string{ + "0b81a958f590ed7ed8be6ec0a2a87816228a482c", + "108f2be974f8e1e5fec8bc759ecf824e81565747", + "4cb7de27c985216b8888ff6049294dae02f3282e", + "c8a693ad89e7069674eda512c553ff56d3ca2ffd", + "4b35e092ad45a626d9a43b7bc7b03e7f7c3c8037", + "c8a693ad89e7069674eda512c553ff56d3ca2ffd-debug", + }, + expected: []string{ + "0b81a958f590ed7ed8be6ec0a2a87816228a482c", + "108f2be974f8e1e5fec8bc759ecf824e81565747", + "4cb7de27c985216b8888ff6049294dae02f3282e", + "c8a693ad89e7069674eda512c553ff56d3ca2ffd", + "4b35e092ad45a626d9a43b7bc7b03e7f7c3c8037", + "c8a693ad89e7069674eda512c553ff56d3ca2ffd-debug", + }, + matchOption: MatchOptionPrefix, + }, + GetOrphanTagsTestCase{ matchValues: []string{ - "v1.0.2", - "2.3", - "1.0", - "v3.1.2", - "v2", + "0b81a958f590ed7ed8be6ec0a2a87816228a482c", + "108f2be974f8e1e5fec8bc759ecf824e81565747", + "4cb7de27c985216b8888ff6049294dae02f3282e", + "c8a693ad89e7069674eda512c553ff56d3ca2ffd", + "4b35e092ad45a626d9a43b7bc7b03e7f7c3c8037", + "c8a693ad89e7069674eda512c553ff56d3ca2ffd-debug", + }, + tags: []string{ + "0b81a958f590ed7ed8be6ec0a2a87816228a482c", + "108f2be974f8e1e5fec8bc759ecf824e81565747", + "4cb7de27c985216b8888ff6049294dae02f3282e", + "c8a693ad89e7069674eda512c553ff56d3ca2ffd", + "4b35e092ad45a626d9a43b7bc7b03e7f7c3c8037", + "c8a693ad89e7069674eda512c553ff56d3ca2ffd-debug", + }, + expected: []string{}, + matchOption: MatchOptionPrefix, + }, + GetOrphanTagsTestCase{ + matchValues: []string{ + "0b81a958f590ed7ed8be6ec0a2a87816228a482c", + "108f2be974f8e1e5fec8bc759ecf824e81565747", + "4cb7de27c985216b8888ff6049294dae02f3282e", + "4b35e092ad45a626d9a43b7bc7b03e7f7c3c8037", + + }, + tags: []string{ + "0b81a958f590ed7ed8be6ec0a2a87816228a482c", + "108f2be974f8e1e5fec8bc759ecf824e81565747", + "4cb7de27c985216b8888ff6049294dae02f3282e", + "c8a693ad89e7069674eda512c553ff56d3ca2ffd", + "4b35e092ad45a626d9a43b7bc7b03e7f7c3c8037", + "c8a693ad89e7069674eda512c553ff56d3ca2ffd-debug", + }, + expected: []string{ + "c8a693ad89e7069674eda512c553ff56d3ca2ffd", + "c8a693ad89e7069674eda512c553ff56d3ca2ffd-debug", + }, + matchOption: MatchOptionPrefix, + }, + GetOrphanTagsTestCase{ + matchValues: []string{ + "3.4", + "0.0.1", + "0.0.2", + "v2.3.0", }, tags: []string{ "1.0", @@ -62,16 +152,16 @@ func Test_GetMatchingTags(t *testing.T) { "0.0.2", "v2.3.0", }, - matchOption: MatchOptionExact, expected: []string{ - "v1.0.2", "1.0", + "v1.0.2", }, + matchOption: MatchOptionExact, }, } for _, testcase := range testcases { - assert.Equal(t, testcase.expected, GetMatchingTags(&testcase.matchValues, &testcase.tags, testcase.matchOption)) + assert.Equal(t, testcase.expected, GetOrphanTags(&testcase.matchValues, &testcase.tags, testcase.matchOption)) } } @@ -106,6 +196,36 @@ func Test_GetInactiveTags(t *testing.T) { } } +func Test_FilterByRegex(t *testing.T) { + reg, err := regexp.Compile("^[a-z0-9]{40}$") + testcases := []FilterByRegexTestCase{ + FilterByRegexTestCase{ + tags: []string{ + "0b81a958f590ed7ed8be6ec0a2a87816228a482c", + "108f2be974f8e1e5fec8bc759ecf824e81565747", + "4cb7de27c985216b8888ff6049294dae02f3282e", + "c8a693ad89e7069674eda512c553ff56d3ca2ffd", + "4b35e092ad45a626d9a43b7bc7b03e7f7c3c8037", + "c8a693ad89e7069674eda512c553ff56d3ca2ffd-debug", + "v2.0", + "v2.0-4", + }, + expected: []string{ + "0b81a958f590ed7ed8be6ec0a2a87816228a482c", + "108f2be974f8e1e5fec8bc759ecf824e81565747", + "4cb7de27c985216b8888ff6049294dae02f3282e", + "c8a693ad89e7069674eda512c553ff56d3ca2ffd", + "4b35e092ad45a626d9a43b7bc7b03e7f7c3c8037", + }, + }, + } + + assert.NoError(t, err) + for _, testcase := range testcases { + assert.Equal(t, testcase.expected, FilterByRegex(&testcase.tags, reg)) + } +} + func Test_LimitTags(t *testing.T) { testcases := []LimitTagsTestCase{ LimitTagsTestCase{ @@ -143,3 +263,65 @@ func Test_LimitTags(t *testing.T) { assert.Equal(t, testcase.expected, LimitTags(&testcase.tags, testcase.limit)) } } + +func Test_TagsOlderThan(t *testing.T) { + testcases := []TagsOlderThanTestCase{ + TagsOlderThanTestCase{ + tags: []imagev1.NamedTagEventList{ + imagev1.NamedTagEventList{ + Tag: "0b81a958f590ed7ed8be6ec0a2a87816228a482c", + Items: []imagev1.TagEvent { + imagev1.TagEvent{ + Created: metav1.Time{ + Time: time.Date(2020, 1, 1,0,0,0,0,time.Local), + }, + }, + imagev1.TagEvent{ + Created: metav1.Time{ + Time: time.Date(2020, 5, 5,0,0,0,0,time.Local), + }, + }, + }, + }, + imagev1.NamedTagEventList{ + Tag: "108f2be974f8e1e5fec8bc759ecf824e81565747", + Items: []imagev1.TagEvent { + imagev1.TagEvent{ + Created: metav1.Time{ + Time: time.Date(2020, 4, 4,0,0,0,0,time.Local), + }, + }, + }, + }, + imagev1.NamedTagEventList{ + Tag: "4cb7de27c985216b8888ff6049294dae02f3282e", + Items: []imagev1.TagEvent { + imagev1.TagEvent{ + Created: metav1.Time{ + Time: time.Date(2020, 3, 3,0,0,0,0,time.Local), + }, + }, + }, + }, + imagev1.NamedTagEventList{ + Tag: "c8a693ad89e7069674eda512c553ff56d3ca2ffd-debug", + Items: []imagev1.TagEvent { + imagev1.TagEvent{ + Created: metav1.Time{ + Time: time.Date(2020, 2, 2,0,0,0,0,time.Local), + }, + }, + }, + }, + }, + expected: []string{ + "c8a693ad89e7069674eda512c553ff56d3ca2ffd-debug", + }, + olderThan: time.Date(2020, 3, 3,0,0,0,0,time.Local), + }, + } + + for _, testcase := range testcases { + assert.Equal(t, testcase.expected, TagsOlderThan(&testcase.tags, testcase.olderThan)) + } +} diff --git a/pkg/git/git.go b/pkg/git/git.go index 2fc1779..fa57213 100644 --- a/pkg/git/git.go +++ b/pkg/git/git.go @@ -7,7 +7,7 @@ import ( "gopkg.in/src-d/go-git.v4" ) -// GetCommitHashes returns the commit hashes of a given repository ordered by the `git.LogOrderCommitterTime`. If `commitLimit` is -1 all commits will be returned. +// GetCommitHashes returns the commit hashes of a given repository ordered by the `git.LogOrderCommitterTime`. If `commitLimit` is 0 all commits will be returned. func GetCommitHashes(repoPath string, commitLimit int) ([]string, error) { var commitHashes []string @@ -22,7 +22,7 @@ func GetCommitHashes(repoPath string, commitLimit int) ([]string, error) { return nil, err } - for i := 0; i < commitLimit || commitLimit < 0; i++ { + for i := 0; i < commitLimit || commitLimit == 0; i++ { commit, err := commitIter.Next() if err != nil { if err == io.EOF { @@ -36,7 +36,7 @@ func GetCommitHashes(repoPath string, commitLimit int) ([]string, error) { return commitHashes, nil } -// GetTags returns the commit tags of a given repository ordered alphabetically or by version. If `commitLimit` is -1 all tags will be returned. +// GetTags returns the commit tags of a given repository ordered alphabetically or by version. If `commitLimit` is 0 all tags will be returned. func GetTags(repoPath string, tagLimit int, sortTagBy SortOption) ([]string, error) { var commitTags []string @@ -51,7 +51,7 @@ func GetTags(repoPath string, tagLimit int, sortTagBy SortOption) ([]string, err return nil, err } - for i := 0; i < tagLimit || tagLimit < 0; i++ { + for i := 0; i < tagLimit || tagLimit == 0; i++ { tag, err := tagIter.Next() if err != nil { diff --git a/pkg/openshift/imagestream.go b/pkg/openshift/imagestream.go index b934215..608e6a9 100644 --- a/pkg/openshift/imagestream.go +++ b/pkg/openshift/imagestream.go @@ -4,6 +4,7 @@ import ( "github.com/appuio/image-cleanup/pkg/kubernetes" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" + imagev1 "github.com/openshift/api/image/v1" ) var ( @@ -63,9 +64,8 @@ func GetImageStreams(namespace string) ([]string, error) { return imageStreams, nil } -// GetImageStreamTags returns the tags of an image stream -func GetImageStreamTags(namespace, imageStreamName string) ([]string, error) { - var imageStreamTags []string +// GetImageStreamTags returns the tags of an image stream older than the specified time +func GetImageStreamTags(namespace, imageStreamName string) ([]imagev1.NamedTagEventList, error) { imageClient, err := NewImageV1Client() if err != nil { @@ -77,13 +77,7 @@ func GetImageStreamTags(namespace, imageStreamName string) ([]string, error) { return nil, err } - imageStreamTags = make([]string, len(imageStream.Status.Tags)) - - for i, imageStreamTag := range imageStream.Status.Tags { - imageStreamTags[i] = imageStreamTag.Tag - } - - return imageStreamTags, nil + return imageStream.Status.Tags, nil } // DeleteImageStreamTag deletes the image stream tag