diff --git a/pkg/feeds/feed_resource.go b/pkg/feeds/feed_resource.go index 0fbb15c1..4c2a6a78 100644 --- a/pkg/feeds/feed_resource.go +++ b/pkg/feeds/feed_resource.go @@ -30,6 +30,9 @@ type FeedResource struct { LayoutRegex string `json:"LayoutRegex,omitempty"` Repository string `json:"Repository,omitempty"` UseMachineCredentials bool `json:"UseMachineCredentials,omitempty"` + UseServiceAccountKey bool `json:"UseServiceAccountKey,omitempty"` + ServiceAccountJsonKey *core.SensitiveValue `json:"ServiceAccountJsonKey,omitempty"` + Project string `json:"Project,omitempty"` resources.Resource } diff --git a/pkg/feeds/feed_types.go b/pkg/feeds/feed_types.go index b767c8b2..6dc61ffd 100644 --- a/pkg/feeds/feed_types.go +++ b/pkg/feeds/feed_types.go @@ -17,4 +17,5 @@ const ( FeedTypeArtifactoryGeneric = FeedType("ArtifactoryGeneric") FeedTypeS3 = FeedType("S3") FeedTypeOCIRegistry = FeedType("OciRegistry") + FeedTypeGcsStorage = FeedType("GcsStorage") ) diff --git a/pkg/feeds/feed_utilities.go b/pkg/feeds/feed_utilities.go index 51889759..412836ab 100644 --- a/pkg/feeds/feed_utilities.go +++ b/pkg/feeds/feed_utilities.go @@ -153,6 +153,20 @@ func ToFeed(feedResource *FeedResource) (IFeed, error) { return nil, err } feed = s3Feed + case FeedTypeGcsStorage: + var googleOidc *GoogleContainerRegistryOidcAuthentication + if feedResource.OidcAuthentication != nil { + if google, ok := feedResource.OidcAuthentication.GetGoogle(); ok { + googleOidc = google + } + } + gcsFeed, err := NewGcsStorageFeed(feedResource.GetName(), feedResource.UseServiceAccountKey, feedResource.ServiceAccountJsonKey, feedResource.Project, googleOidc) + if err != nil { + return nil, err + } + gcsFeed.DownloadAttempts = feedResource.DownloadAttempts + gcsFeed.DownloadRetryBackoffSeconds = feedResource.DownloadRetryBackoffSeconds + feed = gcsFeed case FeedTypeOCIRegistry: ociFeed, err := NewOCIRegistryFeed(feedResource.GetName()) if err != nil { @@ -285,6 +299,19 @@ func ToFeedResource(feed IFeed) (*FeedResource, error) { feedResource.AccessKey = s3Feed.AccessKey feedResource.SecretKey = s3Feed.SecretKey feedResource.UseMachineCredentials = s3Feed.UseMachineCredentials + case FeedTypeGcsStorage: + gcsFeed := feed.(*GcsStorageFeed) + feedResource.DownloadAttempts = gcsFeed.DownloadAttempts + feedResource.DownloadRetryBackoffSeconds = gcsFeed.DownloadRetryBackoffSeconds + feedResource.UseServiceAccountKey = gcsFeed.UseServiceAccountKey + feedResource.ServiceAccountJsonKey = gcsFeed.ServiceAccountJsonKey + feedResource.Project = gcsFeed.Project + if gcsFeed.OidcAuthentication != nil { + feedResource.OidcAuthentication = NewGoogleOidcAuthentication( + gcsFeed.OidcAuthentication.Audience, + gcsFeed.OidcAuthentication.SubjectKeys, + ) + } case FeedTypeOCIRegistry: ociFeed := feed.(*OCIRegistryFeed) feedResource.FeedURI = ociFeed.FeedURI diff --git a/pkg/feeds/gcs_storage_feed.go b/pkg/feeds/gcs_storage_feed.go new file mode 100644 index 00000000..14924bcc --- /dev/null +++ b/pkg/feeds/gcs_storage_feed.go @@ -0,0 +1,60 @@ +package feeds + +import ( + "github.com/OctopusDeploy/go-octopusdeploy/v2/internal" + "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core" + "github.com/go-playground/validator/v10" + "github.com/go-playground/validator/v10/non-standard/validators" +) + +type GcsStorageFeed struct { + UseServiceAccountKey bool `json:"UseServiceAccountKey"` + ServiceAccountJsonKey *core.SensitiveValue `json:"ServiceAccountJsonKey,omitempty"` + Project string `json:"Project,omitempty"` + OidcAuthentication *GoogleContainerRegistryOidcAuthentication `json:"OidcAuthentication,omitempty"` + DownloadAttempts int `json:"DownloadAttempts"` + DownloadRetryBackoffSeconds int `json:"DownloadRetryBackoffSeconds"` + + feed +} + +func NewGcsStorageFeed(name string, useServiceAccountKey bool, serviceAccountJsonKey *core.SensitiveValue, project string, oidcAuthentication *GoogleContainerRegistryOidcAuthentication) (*GcsStorageFeed, error) { + if internal.IsEmpty(name) { + return nil, internal.CreateRequiredParameterIsEmptyOrNilError("name") + } + + if useServiceAccountKey { + if serviceAccountJsonKey == nil || !serviceAccountJsonKey.HasValue { + return nil, internal.CreateRequiredParameterIsEmptyOrNilError("serviceAccountJsonKey") + } + } else { + if oidcAuthentication == nil { + return nil, internal.CreateRequiredParameterIsEmptyOrNilError("oidcAuthentication") + } + } + + feed := GcsStorageFeed{ + UseServiceAccountKey: useServiceAccountKey, + ServiceAccountJsonKey: serviceAccountJsonKey, + Project: project, + OidcAuthentication: oidcAuthentication, + DownloadAttempts: 5, + DownloadRetryBackoffSeconds: 10, + feed: *newFeed(name, FeedTypeGcsStorage), + } + + if err := feed.Validate(); err != nil { + return nil, err + } + + return &feed, nil +} + +func (g *GcsStorageFeed) Validate() error { + v := validator.New() + err := v.RegisterValidation("notblank", validators.NotBlank) + if err != nil { + return err + } + return v.Struct(g) +}