diff --git a/BUILD.bazel b/BUILD.bazel index c2bce60ba5..ffcd9c5898 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -57,7 +57,7 @@ genrule( # gazelle:exclude pkg/model/common.pb.validate.go # gazelle:exclude pkg/model/deployment.pb.validate.go # gazelle:exclude pkg/model/environment.pb.validate.go -# gazelle:exclude pkg/model/imagereference.pb.validate.go +# gazelle:exclude pkg/model/event.pb.validate.go # gazelle:exclude pkg/model/insight.pb.validate.go # gazelle:exclude pkg/model/logblock.pb.validate.go # gazelle:exclude pkg/model/notificationevent.pb.validate.go diff --git a/cmd/pipectl/BUILD.bazel b/cmd/pipectl/BUILD.bazel index a34f29f7f8..7a770a1a8f 100644 --- a/cmd/pipectl/BUILD.bazel +++ b/cmd/pipectl/BUILD.bazel @@ -9,7 +9,7 @@ go_library( deps = [ "//pkg/app/pipectl/cmd/application:go_default_library", "//pkg/app/pipectl/cmd/deployment:go_default_library", - "//pkg/app/pipectl/cmd/image:go_default_library", + "//pkg/app/pipectl/cmd/event:go_default_library", "//pkg/cli:go_default_library", ], ) diff --git a/cmd/pipectl/main.go b/cmd/pipectl/main.go index b6d7b29c78..2efccb4f93 100644 --- a/cmd/pipectl/main.go +++ b/cmd/pipectl/main.go @@ -20,7 +20,7 @@ import ( "github.com/pipe-cd/pipe/pkg/app/pipectl/cmd/application" "github.com/pipe-cd/pipe/pkg/app/pipectl/cmd/deployment" - "github.com/pipe-cd/pipe/pkg/app/pipectl/cmd/image" + "github.com/pipe-cd/pipe/pkg/app/pipectl/cmd/event" "github.com/pipe-cd/pipe/pkg/cli" ) @@ -33,7 +33,7 @@ func main() { app.AddCommands( application.NewCommand(), deployment.NewCommand(), - image.NewCommand(), + event.NewCommand(), ) if err := app.Run(); err != nil { diff --git a/docs/content/en/docs/user-guide/command-line-tool.md b/docs/content/en/docs/user-guide/command-line-tool.md index aa98d57aa4..d6fa71afec 100644 --- a/docs/content/en/docs/user-guide/command-line-tool.md +++ b/docs/content/en/docs/user-guide/command-line-tool.md @@ -186,16 +186,16 @@ pipectl deployment wait-status \ --status=DEPLOYMENT_SUCCESS ``` -### Pushing an image reference +### Registering an event for EventWatcher -Push a new container image reference that can be used by ImageWatcher. +Register an event that can be used by EventWatcher. ``` console -pipectl image push-reference \ +pipectl event register \ --address=CONTROL_PLANE_API_ADDRESS \ --api-key=API_KEY \ - --repo-name=gcr.io/pipecd/example \ - --tag=v0.1.0 + --name=example-image-pushed \ + --data=gcr.io/pipecd/example:v0.1.0 ``` ### You want more? diff --git a/pkg/app/api/grpcapi/api.go b/pkg/app/api/grpcapi/api.go index 9b6b0ade5c..fa4cf67d36 100644 --- a/pkg/app/api/grpcapi/api.go +++ b/pkg/app/api/grpcapi/api.go @@ -34,12 +34,12 @@ import ( // API implements the behaviors for the gRPC definitions of API. type API struct { - applicationStore datastore.ApplicationStore - environmentStore datastore.EnvironmentStore - deploymentStore datastore.DeploymentStore - pipedStore datastore.PipedStore - imageReferenceStore datastore.ImageReferenceStore - commandStore commandstore.Store + applicationStore datastore.ApplicationStore + environmentStore datastore.EnvironmentStore + deploymentStore datastore.DeploymentStore + pipedStore datastore.PipedStore + eventStore datastore.EventStore + commandStore commandstore.Store logger *zap.Logger } @@ -51,13 +51,13 @@ func NewAPI( logger *zap.Logger, ) *API { a := &API{ - applicationStore: datastore.NewApplicationStore(ds), - environmentStore: datastore.NewEnvironmentStore(ds), - deploymentStore: datastore.NewDeploymentStore(ds), - pipedStore: datastore.NewPipedStore(ds), - imageReferenceStore: datastore.NewImageReferenceStore(ds), - commandStore: cmds, - logger: logger.Named("api"), + applicationStore: datastore.NewApplicationStore(ds), + environmentStore: datastore.NewEnvironmentStore(ds), + deploymentStore: datastore.NewDeploymentStore(ds), + pipedStore: datastore.NewPipedStore(ds), + eventStore: datastore.NewEventStore(ds), + commandStore: cmds, + logger: logger.Named("api"), } return a } @@ -314,29 +314,27 @@ func (a *API) GetCommand(ctx context.Context, req *apiservice.GetCommandRequest) }, nil } -func (a *API) PushImageReference(ctx context.Context, req *apiservice.PushImageReferenceRequest) (*apiservice.PushImageReferenceResponse, error) { +func (a *API) RegisterEvent(ctx context.Context, req *apiservice.RegisterEventRequest) (*apiservice.RegisterEventResponse, error) { key, err := requireAPIKey(ctx, model.APIKey_READ_WRITE, a.logger) if err != nil { return nil, err } - im := model.ImageReference{ + err = a.eventStore.AddEvent(ctx, model.Event{ Id: uuid.New().String(), - RepoName: req.RepoName, - Digest: req.Digest, - Tags: req.Tags, + Name: req.Name, + Data: req.Data, ProjectId: key.ProjectId, - } - err = a.imageReferenceStore.AddImageReference(ctx, im) + }) if errors.Is(err, datastore.ErrAlreadyExists) { - return nil, status.Error(codes.AlreadyExists, "The image reference already exists") + return nil, status.Error(codes.AlreadyExists, "The event already exists") } if err != nil { - a.logger.Error("failed to add image reference", zap.Error(err)) - return nil, status.Error(codes.Internal, "Failed to add image reference") + a.logger.Error("failed to register event", zap.Error(err)) + return nil, status.Error(codes.Internal, "Failed to register event") } - return &apiservice.PushImageReferenceResponse{}, nil + return &apiservice.RegisterEventResponse{}, nil } // requireAPIKey checks the existence of an API key inside the given context diff --git a/pkg/app/api/service/apiservice/service.proto b/pkg/app/api/service/apiservice/service.proto index d51cf02c29..f0abc77b1c 100644 --- a/pkg/app/api/service/apiservice/service.proto +++ b/pkg/app/api/service/apiservice/service.proto @@ -35,7 +35,7 @@ service APIService { rpc GetCommand(GetCommandRequest) returns (GetCommandResponse) {} - rpc PushImageReference(PushImageReferenceRequest) returns (PushImageReferenceResponse) {} + rpc RegisterEvent(RegisterEventRequest) returns (RegisterEventResponse) {} } message AddApplicationRequest { @@ -95,11 +95,10 @@ message GetCommandResponse { pipe.model.Command command = 1; } -message PushImageReferenceRequest { - string repo_name = 1 [(validate.rules).string.min_len = 1]; - repeated string tags = 2 [(validate.rules).repeated.min_items = 1]; - string digest = 3; +message RegisterEventRequest { + string name = 1 [(validate.rules).string.min_len = 1]; + string data = 2 [(validate.rules).string.min_len = 1]; } -message PushImageReferenceResponse { +message RegisterEventResponse { } diff --git a/pkg/app/pipectl/cmd/image/BUILD.bazel b/pkg/app/pipectl/cmd/event/BUILD.bazel similarity index 77% rename from pkg/app/pipectl/cmd/image/BUILD.bazel rename to pkg/app/pipectl/cmd/event/BUILD.bazel index d977106023..55a9d12c85 100644 --- a/pkg/app/pipectl/cmd/image/BUILD.bazel +++ b/pkg/app/pipectl/cmd/event/BUILD.bazel @@ -3,10 +3,10 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = [ - "image.go", - "pushreference.go", + "event.go", + "register.go", ], - importpath = "github.com/pipe-cd/pipe/pkg/app/pipectl/cmd/image", + importpath = "github.com/pipe-cd/pipe/pkg/app/pipectl/cmd/event", visibility = ["//visibility:public"], deps = [ "//pkg/app/api/service/apiservice:go_default_library", diff --git a/pkg/app/pipectl/cmd/image/image.go b/pkg/app/pipectl/cmd/event/event.go similarity index 90% rename from pkg/app/pipectl/cmd/image/image.go rename to pkg/app/pipectl/cmd/event/event.go index 8c486a2a04..4e3db5a10c 100644 --- a/pkg/app/pipectl/cmd/image/image.go +++ b/pkg/app/pipectl/cmd/event/event.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package image +package event import ( "github.com/spf13/cobra" @@ -29,12 +29,12 @@ func NewCommand() *cobra.Command { clientOptions: &client.Options{}, } cmd := &cobra.Command{ - Use: "image", - Short: "Manage image resources.", + Use: "event", + Short: "Manage event resources.", } cmd.AddCommand( - newPushReferenceCommand(c), + newRegisterCommand(c), ) c.clientOptions.RegisterPersistentFlags(cmd) diff --git a/pkg/app/pipectl/cmd/event/register.go b/pkg/app/pipectl/cmd/event/register.go new file mode 100644 index 0000000000..134c489143 --- /dev/null +++ b/pkg/app/pipectl/cmd/event/register.go @@ -0,0 +1,72 @@ +// Copyright 2021 The PipeCD Authors. +// +// 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 event + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + + "github.com/pipe-cd/pipe/pkg/app/api/service/apiservice" + "github.com/pipe-cd/pipe/pkg/cli" +) + +type register struct { + root *command + + name string + data string +} + +func newRegisterCommand(root *command) *cobra.Command { + r := ®ister{ + root: root, + } + cmd := &cobra.Command{ + Use: "register", + Short: "Register an event.", + RunE: cli.WithContext(r.run), + } + + cmd.Flags().StringVar(&r.name, "name", r.name, "The name of event.") + cmd.Flags().StringVar(&r.data, "data", r.data, "The string value of event data.") + // TODO: Allow specifying event labels. + + cmd.MarkFlagRequired("name") + cmd.MarkFlagRequired("data") + + return cmd +} + +func (r *register) run(ctx context.Context, t cli.Telemetry) error { + cli, err := r.root.clientOptions.NewClient(ctx) + if err != nil { + return fmt.Errorf("failed to initialize client: %w", err) + } + defer cli.Close() + + req := &apiservice.RegisterEventRequest{ + Name: r.name, + Data: r.data, + } + + if _, err := cli.RegisterEvent(ctx, req); err != nil { + return fmt.Errorf("failed to register event: %w", err) + } + + t.Logger.Info("Successfully registered event") + return nil +} diff --git a/pkg/app/pipectl/cmd/image/pushreference.go b/pkg/app/pipectl/cmd/image/pushreference.go deleted file mode 100644 index ea6c38aee9..0000000000 --- a/pkg/app/pipectl/cmd/image/pushreference.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2021 The PipeCD Authors. -// -// 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 image - -import ( - "context" - "fmt" - - "github.com/spf13/cobra" - - "github.com/pipe-cd/pipe/pkg/app/api/service/apiservice" - "github.com/pipe-cd/pipe/pkg/cli" -) - -type pushReference struct { - root *command - - repoName string - tags []string - digest string -} - -func newPushReferenceCommand(root *command) *cobra.Command { - c := &pushReference{ - root: root, - } - cmd := &cobra.Command{ - Use: "push-reference", - Short: "Push a container image reference.", - RunE: cli.WithContext(c.run), - } - - cmd.Flags().StringVar(&c.repoName, "repo-name", c.repoName, "The repository name of container image. e.g. gcr.io/pipecd/pipecd, envoyproxy/envoy-alpine...") - cmd.Flags().StringSliceVar(&c.tags, "tag", c.tags, "The image tag; Can be used multiple times to set multiple tags.") - cmd.Flags().StringVar(&c.digest, "digest", c.digest, "The image digest.") - - cmd.MarkFlagRequired("repo-name") - cmd.MarkFlagRequired("tag") - - return cmd -} - -func (c *pushReference) run(ctx context.Context, t cli.Telemetry) error { - cli, err := c.root.clientOptions.NewClient(ctx) - if err != nil { - return fmt.Errorf("failed to initialize client: %w", err) - } - defer cli.Close() - - req := &apiservice.PushImageReferenceRequest{ - RepoName: c.repoName, - Tags: c.tags, - Digest: c.digest, - } - - if _, err := cli.PushImageReference(ctx, req); err != nil { - return fmt.Errorf("failed to push image reference: %w", err) - } - - t.Logger.Info("Successfully pushed image reference") - return nil -} diff --git a/pkg/datastore/BUILD.bazel b/pkg/datastore/BUILD.bazel index 5c286a6271..b01f65b054 100644 --- a/pkg/datastore/BUILD.bazel +++ b/pkg/datastore/BUILD.bazel @@ -9,7 +9,7 @@ go_library( "datastore.go", "deploymentstore.go", "environmentstore.go", - "imagereference.go", + "event.go", "mock.go", "pipedstatsstore.go", "pipedstore.go", @@ -32,7 +32,7 @@ go_test( "commandstore_test.go", "deploymentstore_test.go", "environmentstore_test.go", - "imagereference_test.go", + "event_test.go", "pipedstatsstore_test.go", "pipedstore_test.go", "projectstore_test.go", diff --git a/pkg/datastore/imagereference.go b/pkg/datastore/event.go similarity index 56% rename from pkg/datastore/imagereference.go rename to pkg/datastore/event.go index 966d440cfb..e6509dc130 100644 --- a/pkg/datastore/imagereference.go +++ b/pkg/datastore/event.go @@ -21,25 +21,25 @@ import ( "github.com/pipe-cd/pipe/pkg/model" ) -const imageReferenceModelKind = "ImageReference" +const eventModelKind = "Event" var ( - imageReferenceFactory = func() interface{} { - return &model.ImageReference{} + eventFactory = func() interface{} { + return &model.Event{} } ) -type ImageReferenceStore interface { - AddImageReference(ctx context.Context, im model.ImageReference) error +type EventStore interface { + AddEvent(ctx context.Context, e model.Event) error } -type imageReferenceStore struct { +type eventStore struct { backend nowFunc func() time.Time } -func NewImageReferenceStore(ds DataStore) ImageReferenceStore { - return &imageReferenceStore{ +func NewEventStore(ds DataStore) EventStore { + return &eventStore{ backend: backend{ ds: ds, }, @@ -47,16 +47,16 @@ func NewImageReferenceStore(ds DataStore) ImageReferenceStore { } } -func (s *imageReferenceStore) AddImageReference(ctx context.Context, im model.ImageReference) error { +func (s *eventStore) AddEvent(ctx context.Context, e model.Event) error { now := s.nowFunc().Unix() - if im.CreatedAt == 0 { - im.CreatedAt = now + if e.CreatedAt == 0 { + e.CreatedAt = now } - if im.UpdatedAt == 0 { - im.UpdatedAt = now + if e.UpdatedAt == 0 { + e.UpdatedAt = now } - if err := im.Validate(); err != nil { + if err := e.Validate(); err != nil { return err } - return s.ds.Create(ctx, imageReferenceModelKind, im.Id, &im) + return s.ds.Create(ctx, eventModelKind, e.Id, &e) } diff --git a/pkg/datastore/imagereference_test.go b/pkg/datastore/event_test.go similarity index 75% rename from pkg/datastore/imagereference_test.go rename to pkg/datastore/event_test.go index a686d71197..4512afcaaf 100644 --- a/pkg/datastore/imagereference_test.go +++ b/pkg/datastore/event_test.go @@ -24,40 +24,40 @@ import ( "github.com/pipe-cd/pipe/pkg/model" ) -func TestAddImageReference(t *testing.T) { +func TestAddEvent(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - im := model.ImageReference{ + event := model.Event{ Id: "id", - RepoName: "repo", - Tags: []string{"tag"}, - ProjectId: "projectId", + Name: "name", + Data: "data", + ProjectId: "project", CreatedAt: 12345, UpdatedAt: 12345, } testcases := []struct { name string - im model.ImageReference + event model.Event ds DataStore wantErr bool }{ { - name: "Invalid image reference", - im: model.ImageReference{}, + name: "Invalid event", + event: model.Event{}, ds: func() DataStore { return NewMockDataStore(ctrl) }(), wantErr: true, }, { - name: "OK to create", - im: im, + name: "OK", + event: event, ds: func() DataStore { ds := NewMockDataStore(ctrl) ds.EXPECT(). - Create(gomock.Any(), "ImageReference", im.Id, &im). + Create(gomock.Any(), "Event", event.Id, &event). Return(nil) return ds }(), @@ -67,8 +67,8 @@ func TestAddImageReference(t *testing.T) { for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { - s := NewImageReferenceStore(tc.ds) - err := s.AddImageReference(context.Background(), tc.im) + s := NewEventStore(tc.ds) + err := s.AddEvent(context.Background(), tc.event) assert.Equal(t, tc.wantErr, err != nil) }) } diff --git a/pkg/model/BUILD.bazel b/pkg/model/BUILD.bazel index db09715afa..712acabf43 100644 --- a/pkg/model/BUILD.bazel +++ b/pkg/model/BUILD.bazel @@ -11,7 +11,7 @@ proto_library( "common.proto", "deployment.proto", "environment.proto", - "imagereference.proto", + "event.proto", "insight.proto", "logblock.proto", "notificationevent.proto", diff --git a/pkg/model/imagereference.proto b/pkg/model/event.proto similarity index 62% rename from pkg/model/imagereference.proto rename to pkg/model/event.proto index 74ae28c8f2..417bba01ca 100644 --- a/pkg/model/imagereference.proto +++ b/pkg/model/event.proto @@ -19,20 +19,21 @@ option go_package = "github.com/pipe-cd/pipe/pkg/model"; import "validate/validate.proto"; -message ImageReference { +message Event { // The generated unique identifier. string id = 1 [(validate.rules).string.min_len = 1]; - // The repository name. - string repo_name = 2 [(validate.rules).string.min_len = 1]; - // The image digest. - string digest = 3; - // The image tags. - repeated string tags = 4 [(validate.rules).repeated.min_items = 1]; - // The ID of the project this image belongs to. - string project_id = 5 [(validate.rules).string.min_len = 1]; + // The name of event. + string name = 2 [(validate.rules).string.min_len = 1]; + // The data of event. + string data = 3 [(validate.rules).string.min_len = 3]; + // The ID of the project this event belongs to. + string project_id = 4 [(validate.rules).string.min_len = 1]; + // The key/value pairs that are attached to event. + // This is intended to be used to specify additional attributes of event. + map labels = 5; - // Unix time when the image metadata was created. + // Unix time when the event was created. int64 created_at = 14 [(validate.rules).int64.gt = 0]; - // Unix time of the last time when the image metadata is updated. + // Unix time of the last time when the event was updated. int64 updated_at = 15 [(validate.rules).int64.gt = 0]; }