Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend OCM Plugins to support generic actions + define oci.repository.prepare action to assure existence of OCI repositories #320

Merged
merged 8 commits into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ build: ${SOURCES}
go build -ldflags $(BUILD_FLAGS) -o bin/ocm ./cmds/ocm
go build -ldflags $(BUILD_FLAGS) -o bin/helminstaller ./cmds/helminstaller
go build -ldflags $(BUILD_FLAGS) -o bin/demo ./cmds/demoplugin
go build -ldflags $(BUILD_FLAGS) -o bin/ecrplugin ./cmds/ecrplugin


.PHONY: install-requirements
Expand All @@ -37,15 +38,15 @@ prepare: generate format build test check

.PHONY: format
format:
@$(REPO_ROOT)/hack/format.sh $(REPO_ROOT)/pkg $(REPO_ROOT)/cmds/ocm $(REPO_ROOT)/cmds/helminstaller
@$(REPO_ROOT)/hack/format.sh $(REPO_ROOT)/pkg $(REPO_ROOT)/cmds/ocm $(REPO_ROOT)/cmds/helminstaller $(REPO_ROOT)/cmds/ecrplugin $(REPO_ROOT)/cmds/demoplugin

.PHONY: check
check:
@$(REPO_ROOT)/hack/check.sh --golangci-lint-config=./.golangci.yaml $(REPO_ROOT)/cmds/ocm $(REPO_ROOT)/cmds/helminstaller/... $(REPO_ROOT)/pkg/...
@$(REPO_ROOT)/hack/check.sh --golangci-lint-config=./.golangci.yaml $(REPO_ROOT)/cmds/ocm $(REPO_ROOT)/cmds/helminstaller/... $(REPO_ROOT)/cmds/ecrplugin/... $(REPO_ROOT)/cmds/demoplugin/... $(REPO_ROOT)/pkg/...

.PHONY: force-test
force-test:
@go test --count=1 $(REPO_ROOT)/cmds/ocm $(REPO_ROOT)/cmds/helminstaller $(REPO_ROOT)/cmds/ocm/... $(REPO_ROOT)/pkg/...
@go test --count=1 $(REPO_ROOT)/cmds/ocm $(REPO_ROOT)/cmds/helminstaller $(REPO_ROOT)/cmds/ocm/... $(REPO_ROOT)/cmds/ecrplugin/... $(REPO_ROOT)/cmds/demoplugin/... $(REPO_ROOT)/pkg/...

.PHONY: test
test:
Expand Down
8 changes: 5 additions & 3 deletions cmds/demoplugin/accessmethods/demo.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import (
"strings"

"github.com/mandelsoft/filepath/pkg/filepath"
"github.com/open-component-model/ocm/cmds/demoplugin/common"

"github.com/open-component-model/ocm/cmds/demoplugin/common"
"github.com/open-component-model/ocm/cmds/demoplugin/config"
"github.com/open-component-model/ocm/pkg/cobrautils/flagsets"
"github.com/open-component-model/ocm/pkg/contexts/credentials"
Expand All @@ -35,8 +35,10 @@ type AccessSpec struct {
MediaType string `json:"mediaType,omitempty"`
}

const OPT_PATH = "path"
const OPT_MEDIA = "mediaType"
const (
OPT_PATH = "path"
OPT_MEDIA = "mediaType"
)

type AccessMethod struct {
ppi.AccessMethodBase
Expand Down
118 changes: 118 additions & 0 deletions cmds/ecrplugin/actions/action.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors.
//
// SPDX-License-Identifier: Apache-2.0

package actions

import (
"context"
"fmt"
"strings"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/ecr"
"github.com/aws/aws-sdk-go-v2/service/ecr/types"

ocmcreds "github.com/open-component-model/ocm/pkg/contexts/credentials"
oci_repository_prepare "github.com/open-component-model/ocm/pkg/contexts/datacontext/action/types/oci-repository-prepare"
"github.com/open-component-model/ocm/pkg/contexts/ocm/plugin/ppi"
"github.com/open-component-model/ocm/pkg/errors"
)

type Action struct{}

var _ ppi.Action = (*Action)(nil)

func (a Action) Name() string {
return oci_repository_prepare.Type
}

func (a Action) Description() string {
return "Create ECR repository if it does not yet exist."
}

func (a Action) ConsumerType() string {
return "AWS"
}

func (a Action) Execute(p ppi.Plugin, spec ppi.ActionSpec, creds ocmcreds.DirectCredentials) (result ppi.ActionResult, err error) {
prepare, ok := spec.(*oci_repository_prepare.ActionSpec)
if !ok {
return nil, fmt.Errorf("invalid spec type %T", spec)
}

path := strings.Split(prepare.Hostname, ".")
if len(path) < 5 {
return nil, fmt.Errorf("unknown ecr host %q", prepare.Hostname)
}
if path[len(path)-4] != "ecr" {
return nil, fmt.Errorf("unknown ecr host %q", prepare.Hostname)
}
region := path[len(path)-3]
ctx := context.Background()
opts := []func(*config.LoadOptions) error{
config.WithRegion(region),
}

var awsCred aws.CredentialsProvider = aws.AnonymousCredentials{}

if creds != nil {
accessKeyID := creds.GetProperty(ocmcreds.ATTR_AWS_ACCESS_KEY_ID)
accessSecret := creds.GetProperty(ocmcreds.ATTR_AWS_SECRET_ACCESS_KEY)
accessToken := creds.GetProperty(ocmcreds.ATTR_TOKEN)
awsCred = credentials.NewStaticCredentialsProvider(accessKeyID, accessSecret, accessToken)
}

opts = append(opts, config.WithCredentialsProvider(awsCred))
cfg, err := config.LoadDefaultConfig(ctx, opts...)
if err != nil {
return nil, fmt.Errorf("failed to load configuration for AWS: %w", err)
}

client := ecr.NewFromConfig(cfg, func(o *ecr.Options) {
// Pass in creds because of https://github.com/aws/aws-sdk-go-v2/issues/1797
o.Credentials = awsCred
o.Region = region
})

msg := fmt.Sprintf("repository %q already exists in region %s", prepare.Repository, region)
in := &ecr.DescribeRepositoriesInput{
RepositoryNames: []string{prepare.Repository},
}
_, err = client.DescribeRepositories(ctx, in)
if err != nil {
var rnf *types.RepositoryNotFoundException
if errors.As(err, &rnf) {
in := &ecr.CreateRepositoryInput{
RepositoryName: aws.String(prepare.Repository),
Tags: []types.Tag{
{
Key: aws.String("ocm"),
Value: aws.String("ecrplugin"),
},
},
}
_, err := client.CreateRepository(ctx, in)
if err != nil {
var re *types.RepositoryAlreadyExistsException
if errors.As(err, &re) {
return oci_repository_prepare.Result(msg), nil
}
return nil, err
}
return oci_repository_prepare.Result(fmt.Sprintf("repository %q created in region %s", prepare.Repository, region)), nil
}
return nil, err
}
return oci_repository_prepare.Result(msg), nil
}

func (a *Action) DefaultSelectors() []string {
return []string{".*\\.dkr\\.ecr\\..*\\.amazonaws\\.com"}
}

func New() ppi.Action {
return &Action{}
}
23 changes: 23 additions & 0 deletions cmds/ecrplugin/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors.
//
// SPDX-License-Identifier: Apache-2.0

package config

import (
"encoding/json"
)

type Config struct {
Hostnames []string `json:"hostnames,omitempty"`
}

func GetConfig(raw json.RawMessage) (interface{}, error) {
var cfg Config

err := json.Unmarshal(raw, &cfg)
if err != nil {
return nil, err
}
return &cfg, nil
}
16 changes: 16 additions & 0 deletions cmds/ecrplugin/config/tweak.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Open Component Model contributors.
//
// SPDX-License-Identifier: Apache-2.0

package config

import (
"github.com/open-component-model/ocm/pkg/contexts/ocm/plugin/ppi"
)

func TweakDescriptor(d ppi.Descriptor, cfg *Config) ppi.Descriptor {
if cfg != nil {
d.Actions[0].DefaultSelectors = append(d.Actions[0].DefaultSelectors, cfg.Hostnames...)
}
return d
}
36 changes: 36 additions & 0 deletions cmds/ecrplugin/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors.
//
// SPDX-License-Identifier: Apache-2.0

package main

import (
"os"

"github.com/open-component-model/ocm/cmds/ecrplugin/actions"
"github.com/open-component-model/ocm/cmds/ecrplugin/config"
"github.com/open-component-model/ocm/pkg/contexts/ocm/plugin/ppi"
"github.com/open-component-model/ocm/pkg/contexts/ocm/plugin/ppi/cmds"
"github.com/open-component-model/ocm/pkg/version"
)

func main() {
p := ppi.NewPlugin("ecrplugin", version.Get().String())

p.SetShort("AWS ecr repository creation")
p.SetLong("plugin assuring the existence of required AWS ECR repositories")
p.SetConfigParser(config.GetConfig)
p.SetDescriptorTweaker(func(d ppi.Descriptor) ppi.Descriptor {
cfg, _ := p.GetConfig()
if cfg == nil {
return d
}
return config.TweakDescriptor(d, cfg.(*config.Config))
})

p.RegisterAction(actions.New())
err := cmds.NewPluginCommand(p).Execute(os.Args[1:])
if err != nil {
os.Exit(1)
}
}
4 changes: 4 additions & 0 deletions cmds/ocm/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package app
import (
"strings"

"github.com/open-component-model/ocm/cmds/ocm/commands/misccmds/action"
_ "github.com/open-component-model/ocm/pkg/contexts/clictx/config"
_ "github.com/open-component-model/ocm/pkg/contexts/ocm/attrs"

Expand Down Expand Up @@ -39,6 +40,7 @@ import (
"github.com/open-component-model/ocm/cmds/ocm/commands/verbs/create"
"github.com/open-component-model/ocm/cmds/ocm/commands/verbs/describe"
"github.com/open-component-model/ocm/cmds/ocm/commands/verbs/download"
"github.com/open-component-model/ocm/cmds/ocm/commands/verbs/execute"
"github.com/open-component-model/ocm/cmds/ocm/commands/verbs/get"
"github.com/open-component-model/ocm/cmds/ocm/commands/verbs/hash"
"github.com/open-component-model/ocm/cmds/ocm/commands/verbs/install"
Expand Down Expand Up @@ -198,6 +200,7 @@ func newCliCommand(opts *CLIOptions, mod ...func(clictx.Context, *cobra.Command)
cmd.AddCommand(bootstrap.NewCommand(opts.Context))
cmd.AddCommand(clean.NewCommand(opts.Context))
cmd.AddCommand(install.NewCommand(opts.Context))
cmd.AddCommand(execute.NewCommand(opts.Context))
cmd.AddCommand(controller.NewCommand(opts.Context))

cmd.AddCommand(cmdutils.HideCommand(componentarchive.NewCommand(opts.Context)))
Expand All @@ -206,6 +209,7 @@ func newCliCommand(opts *CLIOptions, mod ...func(clictx.Context, *cobra.Command)
cmd.AddCommand(cmdutils.HideCommand(sources.NewCommand(opts.Context)))
cmd.AddCommand(cmdutils.HideCommand(components.NewCommand(opts.Context)))
cmd.AddCommand(cmdutils.HideCommand(plugins.NewCommand(opts.Context)))
cmd.AddCommand(cmdutils.HideCommand(action.NewCommand(opts.Context)))

cmd.AddCommand(cmdutils.HideCommand(cachecmds.NewCommand(opts.Context)))
cmd.AddCommand(cmdutils.HideCommand(ocicmds.NewCommand(opts.Context)))
Expand Down
29 changes: 29 additions & 0 deletions cmds/ocm/commands/misccmds/action/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors.
//
// SPDX-License-Identifier: Apache-2.0

package action

import (
"github.com/spf13/cobra"

"github.com/open-component-model/ocm/cmds/ocm/commands/misccmds/action/execute"
"github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/names"
"github.com/open-component-model/ocm/cmds/ocm/pkg/utils"
"github.com/open-component-model/ocm/pkg/contexts/clictx"
)

var Names = names.Action

// NewCommand creates a new command.
func NewCommand(ctx clictx.Context) *cobra.Command {
cmd := utils.MassageCommand(&cobra.Command{
Short: "Commands acting on actions",
}, Names...)
AddCommands(ctx, cmd)
return cmd
}

func AddCommands(ctx clictx.Context, cmd *cobra.Command) {
cmd.AddCommand(execute.NewCommand(ctx, execute.Verb))
}
Loading