From f2f1a4491b4284b9e775a8882728d3365a5bc680 Mon Sep 17 00:00:00 2001 From: Avinal Kumar Date: Thu, 14 Mar 2024 14:10:06 +0530 Subject: [PATCH] Add log stored status explicitly - adding log stored stored status explictly in the Log object improves the detection for partial or no storage of logs - it might help mitigate the race condition between pruning the runs and storing the logs. Signed-off-by: Avinal Kumar Signed-off-by: Khurram Baig --- pkg/api/server/v1alpha2/log/file.go | 6 +- pkg/api/server/v1alpha2/log/gcs.go | 6 +- pkg/api/server/v1alpha2/log/log.go | 22 ++-- pkg/api/server/v1alpha2/log/log_test.go | 26 ++--- pkg/api/server/v1alpha2/log/s3.go | 6 +- pkg/api/server/v1alpha2/logs.go | 36 ++++-- pkg/api/server/v1alpha2/logs_test.go | 133 ++++++++++++++++++----- pkg/api/server/v1alpha2/record/record.go | 8 +- pkg/apis/{v1alpha2 => v1alpha3}/types.go | 15 ++- pkg/watcher/convert/convert.go | 10 +- pkg/watcher/convert/convert_test.go | 10 +- 11 files changed, 188 insertions(+), 90 deletions(-) rename pkg/apis/{v1alpha2 => v1alpha3}/types.go (79%) diff --git a/pkg/api/server/v1alpha2/log/file.go b/pkg/api/server/v1alpha2/log/file.go index a8ba2b8c3..84c121e76 100644 --- a/pkg/api/server/v1alpha2/log/file.go +++ b/pkg/api/server/v1alpha2/log/file.go @@ -10,7 +10,7 @@ import ( "github.com/tektoncd/results/pkg/api/server/config" - "github.com/tektoncd/results/pkg/apis/v1alpha2" + "github.com/tektoncd/results/pkg/apis/v1alpha3" ) type fileStream struct { @@ -20,7 +20,7 @@ type fileStream struct { } // NewFileStream returns a LogStreamer that streams directly from a log file on local disk. -func NewFileStream(ctx context.Context, log *v1alpha2.Log, config *config.Config) (Stream, error) { +func NewFileStream(ctx context.Context, log *v1alpha3.Log, config *config.Config) (Stream, error) { if log.Status.Path == "" { filePath, err := FilePath(log) if err != nil { @@ -42,7 +42,7 @@ func NewFileStream(ctx context.Context, log *v1alpha2.Log, config *config.Config } func (*fileStream) Type() string { - return string(v1alpha2.FileLogType) + return string(v1alpha3.FileLogType) } // WriteTo reads the contents of the TaskRun log file and writes them to the provided writer, such diff --git a/pkg/api/server/v1alpha2/log/gcs.go b/pkg/api/server/v1alpha2/log/gcs.go index 0ed945aad..eadb2c8f7 100644 --- a/pkg/api/server/v1alpha2/log/gcs.go +++ b/pkg/api/server/v1alpha2/log/gcs.go @@ -27,7 +27,7 @@ import ( "os" server "github.com/tektoncd/results/pkg/api/server/config" - "github.com/tektoncd/results/pkg/apis/v1alpha2" + "github.com/tektoncd/results/pkg/apis/v1alpha3" "gocloud.dev/blob/gcsblob" "gocloud.dev/gcp" @@ -41,7 +41,7 @@ type gcsStream struct { } // NewGCSStream returns a log streamer for the GCS storage type. -func NewGCSStream(ctx context.Context, log *v1alpha2.Log, config *server.Config) (Stream, error) { +func NewGCSStream(ctx context.Context, log *v1alpha3.Log, config *server.Config) (Stream, error) { if log.Status.Path == "" { filePath, err := FilePath(log) if err != nil { @@ -89,7 +89,7 @@ func getGCSClient(ctx context.Context, cfg *server.Config) (*gcp.HTTPClient, err } func (*gcsStream) Type() string { - return string(v1alpha2.GCSLogType) + return string(v1alpha3.GCSLogType) } func (gcs *gcsStream) WriteTo(w io.Writer) (int64, error) { diff --git a/pkg/api/server/v1alpha2/log/log.go b/pkg/api/server/v1alpha2/log/log.go index 41e60d72e..affd531a6 100644 --- a/pkg/api/server/v1alpha2/log/log.go +++ b/pkg/api/server/v1alpha2/log/log.go @@ -10,7 +10,7 @@ import ( "github.com/tektoncd/results/pkg/api/server/config" "github.com/tektoncd/results/pkg/api/server/db" - "github.com/tektoncd/results/pkg/apis/v1alpha2" + "github.com/tektoncd/results/pkg/apis/v1alpha3" pb "github.com/tektoncd/results/proto/v1alpha2/results_go_proto" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -64,13 +64,13 @@ type Stream interface { // // NewStream may mutate the Log object's status, to provide implementation information // for reading and writing files. -func NewStream(ctx context.Context, log *v1alpha2.Log, config *config.Config) (Stream, error) { +func NewStream(ctx context.Context, log *v1alpha3.Log, config *config.Config) (Stream, error) { switch log.Spec.Type { - case v1alpha2.FileLogType: + case v1alpha3.FileLogType: return NewFileStream(ctx, log, config) - case v1alpha2.S3LogType: + case v1alpha3.S3LogType: return NewS3Stream(ctx, log, config) - case v1alpha2.GCSLogType: + case v1alpha3.GCSLogType: return NewGCSStream(ctx, log, config) } return nil, fmt.Errorf("log streamer type %s is not supported", log.Spec.Type) @@ -78,7 +78,7 @@ func NewStream(ctx context.Context, log *v1alpha2.Log, config *config.Config) (S // ToStorage converts log record to marshaled json bytes func ToStorage(record *pb.Record, config *config.Config) ([]byte, error) { - log := &v1alpha2.Log{} + log := &v1alpha3.Log{} if len(record.GetData().Value) > 0 { err := json.Unmarshal(record.GetData().Value, log) if err != nil { @@ -88,7 +88,7 @@ func ToStorage(record *pb.Record, config *config.Config) ([]byte, error) { log.Default() if log.Spec.Type == "" { - log.Spec.Type = v1alpha2.LogType(config.LOGS_TYPE) + log.Spec.Type = v1alpha3.LogType(config.LOGS_TYPE) if len(log.Spec.Type) == 0 { return nil, fmt.Errorf("failed to set up log storage type to spec") } @@ -100,11 +100,11 @@ func ToStorage(record *pb.Record, config *config.Config) ([]byte, error) { // First one is a new log streamer created by log record. // Second one is log API resource retrieved from log record. // Third argument is an error. -func ToStream(ctx context.Context, record *db.Record, config *config.Config) (Stream, *v1alpha2.Log, error) { - if record.Type != v1alpha2.LogRecordType { +func ToStream(ctx context.Context, record *db.Record, config *config.Config) (Stream, *v1alpha3.Log, error) { + if record.Type != v1alpha3.LogRecordType && record.Type != v1alpha3.LogRecordTypeV2 { return nil, nil, fmt.Errorf("record type %s cannot stream logs", record.Type) } - log := &v1alpha2.Log{} + log := &v1alpha3.Log{} err := json.Unmarshal(record.Data, log) if err != nil { return nil, nil, fmt.Errorf("could not decode Log record: %w", err) @@ -115,7 +115,7 @@ func ToStream(ctx context.Context, record *db.Record, config *config.Config) (St // FilePath returns file path to store log. This file path can be // path in the real file system or virtual value depending on storage type. -func FilePath(log *v1alpha2.Log) (string, error) { +func FilePath(log *v1alpha3.Log) (string, error) { filePath := filepath.Join(log.GetNamespace(), string(log.GetUID()), log.Name) if filePath == "" { return "", fmt.Errorf("invalid file path") diff --git a/pkg/api/server/v1alpha2/log/log_test.go b/pkg/api/server/v1alpha2/log/log_test.go index 15e05d80b..8553d5690 100644 --- a/pkg/api/server/v1alpha2/log/log_test.go +++ b/pkg/api/server/v1alpha2/log/log_test.go @@ -10,14 +10,14 @@ import ( "github.com/tektoncd/results/pkg/api/server/config" "github.com/tektoncd/results/pkg/api/server/db" - "github.com/tektoncd/results/pkg/apis/v1alpha2" + "github.com/tektoncd/results/pkg/apis/v1alpha3" "github.com/tektoncd/results/pkg/internal/jsonutil" pb "github.com/tektoncd/results/proto/v1alpha2/results_go_proto" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func TestFilePath(t *testing.T) { - log := &v1alpha2.Log{ + log := &v1alpha3.Log{ ObjectMeta: v1.ObjectMeta{ Name: "test-log", Namespace: "test", @@ -112,13 +112,13 @@ func TestParseName(t *testing.T) { } func TestToStorage(t *testing.T) { - log := &v1alpha2.Log{ + log := &v1alpha3.Log{ ObjectMeta: v1.ObjectMeta{ Name: "test-taskrun-log", }, - Spec: v1alpha2.LogSpec{ - Type: v1alpha2.FileLogType, - Resource: v1alpha2.Resource{ + Spec: v1alpha3.LogSpec{ + Type: v1alpha3.FileLogType, + Resource: v1alpha3.Resource{ Name: "test-taskrun", }, }, @@ -133,7 +133,7 @@ func TestToStorage(t *testing.T) { rec := &pb.Record{ Name: "test-log", Data: &pb.Any{ - Type: v1alpha2.LogRecordType, + Type: v1alpha3.LogRecordType, Value: want, }, } @@ -183,16 +183,16 @@ func TestToStream(t *testing.T) { ResultName: "push-main", Name: "taskrun-compile-log", ID: "a", - Type: v1alpha2.LogRecordType, - Data: jsonutil.AnyBytes(t, &v1alpha2.Log{ + Type: v1alpha3.LogRecordType, + Data: jsonutil.AnyBytes(t, &v1alpha3.Log{ ObjectMeta: v1.ObjectMeta{ Name: "test-log", Namespace: "test", UID: "test-uid", }, - Spec: v1alpha2.LogSpec{ - Type: v1alpha2.FileLogType, - Resource: v1alpha2.Resource{ + Spec: v1alpha3.LogSpec{ + Type: v1alpha3.FileLogType, + Resource: v1alpha3.Resource{ Namespace: "app", Name: "taskrun-compile", }, @@ -200,7 +200,7 @@ func TestToStream(t *testing.T) { }), }, want: &mockStream{ - streamType: string(v1alpha2.FileLogType), + streamType: string(v1alpha3.FileLogType), }, }, { diff --git a/pkg/api/server/v1alpha2/log/s3.go b/pkg/api/server/v1alpha2/log/s3.go index d72cb4108..3eeff823d 100644 --- a/pkg/api/server/v1alpha2/log/s3.go +++ b/pkg/api/server/v1alpha2/log/s3.go @@ -17,7 +17,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/s3/types" server "github.com/tektoncd/results/pkg/api/server/config" - "github.com/tektoncd/results/pkg/apis/v1alpha2" + "github.com/tektoncd/results/pkg/apis/v1alpha3" ) const ( @@ -49,7 +49,7 @@ type s3Stream struct { } // NewS3Stream returns a log streamer for the S3 log storage type. -func NewS3Stream(ctx context.Context, log *v1alpha2.Log, config *server.Config) (Stream, error) { +func NewS3Stream(ctx context.Context, log *v1alpha3.Log, config *server.Config) (Stream, error) { if log.Status.Path == "" { filePath, err := FilePath(log) if err != nil { @@ -130,7 +130,7 @@ func initConfig(ctx context.Context, cfg *server.Config) (*s3.Client, error) { } func (*s3Stream) Type() string { - return string(v1alpha2.S3LogType) + return string(v1alpha3.S3LogType) } func (s3s *s3Stream) WriteTo(w io.Writer) (n int64, err error) { diff --git a/pkg/api/server/v1alpha2/logs.go b/pkg/api/server/v1alpha2/logs.go index c46e75c7a..9765425a3 100644 --- a/pkg/api/server/v1alpha2/logs.go +++ b/pkg/api/server/v1alpha2/logs.go @@ -21,7 +21,7 @@ import ( "github.com/tektoncd/results/pkg/api/server/v1alpha2/auth" "github.com/tektoncd/results/pkg/api/server/v1alpha2/log" "github.com/tektoncd/results/pkg/api/server/v1alpha2/record" - "github.com/tektoncd/results/pkg/apis/v1alpha2" + "github.com/tektoncd/results/pkg/apis/v1alpha3" "github.com/tektoncd/results/pkg/logs" pb "github.com/tektoncd/results/proto/v1alpha2/results_go_proto" "google.golang.org/protobuf/types/known/timestamppb" @@ -47,7 +47,7 @@ func (s *Server) GetLog(req *pb.GetLogRequest, srv pb.Logs_GetLogServer) error { return err } // Check if the input record is referenced in any logs record in the result - if rec.Type != v1alpha2.LogRecordType { + if rec.Type != v1alpha3.LogRecordType && rec.Type != v1alpha3.LogRecordTypeV2 { rec, err = getLogRecord(s.db, parent, res, name) if err != nil { s.logger.Error(err) @@ -60,9 +60,20 @@ func (s *Server) GetLog(req *pb.GetLogRequest, srv pb.Logs_GetLogServer) error { s.logger.Error(err) return status.Error(codes.Internal, "Error streaming log") } - if object.Status.Size == 0 { - s.logger.Errorf("no logs exist for %s", req.GetName()) - return status.Error(codes.NotFound, "Log doesn't exist") + + // Handle v1alpha2 and earlier differently from v1alpha3 until v1alpha2 and earlier are deprecated + if "results.tekton.dev/v1alpha3" == object.APIVersion { + if !object.Status.IsStored || object.Status.Size == 0 { + s.logger.Errorf("no logs exist for %s", req.GetName()) + return status.Error(codes.NotFound, "Log doesn't exist") + } + } else { + // For v1alpha2 checking log size is the best way to ensure if logs are stored + // this is however susceptible to race condition + if object.Status.Size == 0 { + s.logger.Errorf("no logs exist for %s", req.GetName()) + return status.Error(codes.NotFound, "Log doesn't exist") + } } writer := logs.NewBufferedHTTPWriter(srv, req.GetName(), s.config.LOGS_BUFFER_SIZE) @@ -95,7 +106,7 @@ func (s *Server) UpdateLog(srv pb.Logs_UpdateLogServer) error { var name, parent, resultName, recordName string var bytesWritten int64 var rec *db.Record - var object *v1alpha2.Log + var object *v1alpha3.Log var stream log.Stream // fyi we cannot defer the flush call in case we need to return the error // but instead we pass the stream into handleError to preserve the behavior of @@ -162,7 +173,7 @@ func (s *Server) UpdateLog(srv pb.Logs_UpdateLogServer) error { } } -func (s *Server) handleReturn(srv pb.Logs_UpdateLogServer, rec *db.Record, log *v1alpha2.Log, written int64, stream log.Stream, returnErr error) error { +func (s *Server) handleReturn(srv pb.Logs_UpdateLogServer, rec *db.Record, log *v1alpha3.Log, written int64, stream log.Stream, returnErr error) error { // When the srv reaches the end, srv.Recv() returns an io.EOF error // Therefore we should not return io.EOF if it is received in this function. // Otherwise, we should return the original error and not mask any subsequent errors handling cleanup/return. @@ -184,9 +195,12 @@ func (s *Server) handleReturn(srv pb.Logs_UpdateLogServer, rec *db.Record, log * } apiRec := record.ToAPI(rec) apiRec.UpdateTime = timestamppb.Now() - if written > 0 { - log.Status.Size = written + log.Status.Size = written + log.Status.IsStored = returnErr == io.EOF + if returnErr != nil && returnErr != io.EOF { + log.Status.ErrorOnStoreMsg = returnErr.Error() } + data, err := json.Marshal(log) if err != nil { if stream != nil { @@ -327,7 +341,7 @@ func (s *Server) getFilteredPaginatedSortedLogRecords(ctx context.Context, paren for len(rec) < pageSize { batchSize := batcher.Next() dbrecords := make([]*db.Record, 0, batchSize) - q := s.db.WithContext(ctx).Where("type = ?", v1alpha2.LogRecordType) + q := s.db.WithContext(ctx).Where("type = ?", v1alpha3.LogRecordType) q = q.Where("id > ?", start) // Specifying `-` allows users to read Records across Results. // See https://google.aip.dev/159 for more details. @@ -397,7 +411,7 @@ func (s *Server) DeleteLog(ctx context.Context, req *pb.DeleteLogRequest) (*empt return &empty.Empty{}, err } // Check if the input record is referenced in any logs record - if rec.Type != v1alpha2.LogRecordType { + if rec.Type != v1alpha3.LogRecordType { rec, err = getLogRecord(s.db, parent, res, name) if err != nil { return &empty.Empty{}, err diff --git a/pkg/api/server/v1alpha2/logs_test.go b/pkg/api/server/v1alpha2/logs_test.go index beb3f14a3..3a783acb5 100644 --- a/pkg/api/server/v1alpha2/logs_test.go +++ b/pkg/api/server/v1alpha2/logs_test.go @@ -22,7 +22,7 @@ import ( "github.com/tektoncd/results/pkg/api/server/v1alpha2/log" "github.com/tektoncd/results/pkg/api/server/v1alpha2/record" "github.com/tektoncd/results/pkg/api/server/v1alpha2/result" - "github.com/tektoncd/results/pkg/apis/v1alpha2" + "github.com/tektoncd/results/pkg/apis/v1alpha3" "github.com/tektoncd/results/pkg/internal/jsonutil" pb "github.com/tektoncd/results/proto/v1alpha2/results_go_proto" "google.golang.org/grpc/codes" @@ -128,19 +128,98 @@ func TestGetLog(t *testing.T) { Record: &pb.Record{ Name: record.FormatName(res.GetName(), "baz"), Data: &pb.Any{ - Type: v1alpha2.LogRecordType, - Value: jsonutil.AnyBytes(t, &v1alpha2.Log{ - Spec: v1alpha2.LogSpec{ - Resource: v1alpha2.Resource{ + Type: v1alpha3.LogRecordTypeV2, + Value: jsonutil.AnyBytes(t, &v1alpha3.Log{ + Spec: v1alpha3.LogSpec{ + Resource: v1alpha3.Resource{ Namespace: "foo", Name: "baz", }, - Type: v1alpha2.FileLogType, + Type: v1alpha3.FileLogType, }, // To avoid defaulting behavior, explicitly set the file path in status - Status: v1alpha2.LogStatus{ - Path: logFile.Name(), - Size: 1024, + Status: v1alpha3.LogStatus{ + Path: logFile.Name(), + Size: 1024, + IsStored: true, + }, + }), + }, + }, + }) + if err != nil { + t.Fatalf("CreateRecord: %v", err) + } + + err = srv.GetLog(&pb.GetLogRequest{ + Name: log.FormatName(res.GetName(), "baz"), + }, mock) + if err != nil { + t.Fatalf("failed to get log: %v", err) + } + actualData := mock.receivedData.String() + if expectedData != actualData { + t.Errorf("expected to have received %q, got %q", expectedData, actualData) + } +} + +func TestGetLogV2(t *testing.T) { + srv, err := New(&config.Config{ + LOGS_API: true, + LOGS_TYPE: "File", + DB_ENABLE_AUTO_MIGRATION: true, + }, logger.Get("info"), test.NewDB(t)) + if err != nil { + t.Fatalf("failed to create server: %v", err) + } + ctx := context.Background() + mock := &mockGetLogServer{ + ctx: ctx, + } + res, err := srv.CreateResult(ctx, &pb.CreateResultRequest{ + Parent: "foo", + Result: &pb.Result{ + Name: "foo/results/bar", + }, + }) + if err != nil { + t.Fatalf("CreateResult: %v", err) + } + + expectedData := "Hello World!" + logFile, err := os.CreateTemp("", "test-log-taskrun-*.log") + t.Log("test log file: ", logFile.Name()) + t.Cleanup(func() { + logFile.Close() + os.Remove(logFile.Name()) + }) + if err != nil { + t.Fatalf("failed to create tempfile: %v", err) + } + _, err = logFile.Write([]byte(expectedData)) + if err != nil { + t.Fatalf("failed to write to tempfile: %v", err) + } + + _, err = srv.CreateRecord(ctx, &pb.CreateRecordRequest{ + Parent: res.GetName(), + Record: &pb.Record{ + Name: record.FormatName(res.GetName(), "baz"), + Data: &pb.Any{ + Type: v1alpha3.LogRecordType, + Value: jsonutil.AnyBytes(t, &v1alpha3.Log{ + Spec: v1alpha3.LogSpec{ + Resource: v1alpha3.Resource{ + Namespace: "foo", + Name: "baz", + }, + Type: v1alpha3.FileLogType, + }, + // To avoid defaulting behavior, explicitly set the file path in status + Status: v1alpha3.LogStatus{ + Path: logFile.Name(), + Size: 1024, + IsStored: true, }, }), }, @@ -197,21 +276,21 @@ func TestUpdateLog(t *testing.T) { Record: &pb.Record{ Name: recordName, Data: &pb.Any{ - Type: v1alpha2.LogRecordType, - Value: jsonutil.AnyBytes(t, &v1alpha2.Log{ + Type: v1alpha3.LogRecordType, + Value: jsonutil.AnyBytes(t, &v1alpha3.Log{ ObjectMeta: metav1.ObjectMeta{ Name: "test-name", UID: "test-uid", }, - Spec: v1alpha2.LogSpec{ - Resource: v1alpha2.Resource{ + Spec: v1alpha3.LogSpec{ + Resource: v1alpha3.Resource{ Namespace: "foo", Name: "baz", }, - Type: v1alpha2.FileLogType, + Type: v1alpha3.FileLogType, }, // To avoid defaulting behavior, explicitly set the file path in status - Status: v1alpha2.LogStatus{ + Status: v1alpha3.LogStatus{ Path: path, }, }), @@ -276,8 +355,8 @@ func TestListLogs(t *testing.T) { Record: &pb.Record{ Name: fmt.Sprintf("%s/records/%d", res.GetName(), i), Data: &pb.Any{ - Type: v1alpha2.LogRecordType, - Value: jsonutil.AnyBytes(t, &v1alpha2.Log{ + Type: v1alpha3.LogRecordType, + Value: jsonutil.AnyBytes(t, &v1alpha3.Log{ ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%d", i), }, @@ -374,12 +453,12 @@ func TestListLogs(t *testing.T) { name: "filter and page size", req: &pb.ListRecordsRequest{ Parent: res.GetName(), - Filter: `data_type == "results.tekton.dev/v1alpha2.Log"`, + Filter: `data_type == "results.tekton.dev/v1alpha3.Log"`, PageSize: 1, }, want: &pb.ListRecordsResponse{ Records: records[:1], - NextPageToken: pagetoken(t, records[1].GetUid(), `data_type == "results.tekton.dev/v1alpha2.Log"`), + NextPageToken: pagetoken(t, records[1].GetUid(), `data_type == "results.tekton.dev/v1alpha3.Log"`), }, }, { @@ -533,8 +612,8 @@ func TestListLogs_multiresult(t *testing.T) { Record: &pb.Record{ Name: record.FormatName(res.GetName(), strconv.Itoa(k)), Data: &pb.Any{ - Type: v1alpha2.LogRecordType, - Value: jsonutil.AnyBytes(t, &v1alpha2.Log{ + Type: v1alpha3.LogRecordType, + Value: jsonutil.AnyBytes(t, &v1alpha3.Log{ ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%d", k), }, @@ -609,17 +688,17 @@ func TestDeleteLog(t *testing.T) { Record: &pb.Record{ Name: record.FormatName(res.GetName(), "baz"), Data: &pb.Any{ - Type: v1alpha2.LogRecordType, - Value: jsonutil.AnyBytes(t, &v1alpha2.Log{ - Spec: v1alpha2.LogSpec{ - Resource: v1alpha2.Resource{ + Type: v1alpha3.LogRecordType, + Value: jsonutil.AnyBytes(t, &v1alpha3.Log{ + Spec: v1alpha3.LogSpec{ + Resource: v1alpha3.Resource{ Namespace: "foo", Name: "baz", }, - Type: v1alpha2.FileLogType, + Type: v1alpha3.FileLogType, }, // To avoid defaulting behavior, explicitly set the file path in status - Status: v1alpha2.LogStatus{ + Status: v1alpha3.LogStatus{ Path: logFile.Name(), Size: 1024, }, diff --git a/pkg/api/server/v1alpha2/record/record.go b/pkg/api/server/v1alpha2/record/record.go index 21e3f332b..1f4ca897b 100644 --- a/pkg/api/server/v1alpha2/record/record.go +++ b/pkg/api/server/v1alpha2/record/record.go @@ -22,7 +22,7 @@ import ( "github.com/tektoncd/results/pkg/api/server/config" "github.com/tektoncd/results/pkg/api/server/v1alpha2/log" - "github.com/tektoncd/results/pkg/apis/v1alpha2" + "github.com/tektoncd/results/pkg/apis/v1alpha3" "github.com/google/cel-go/cel" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" @@ -98,7 +98,7 @@ func ToStorage(parent, resultName, resultID, name string, r *pb.Record, config * if r.UpdateTime.IsValid() { dbr.UpdatedTime = r.UpdateTime.AsTime() } - if dbr.Type == v1alpha2.LogRecordType { + if dbr.Type == v1alpha3.LogRecordType || dbr.Type == v1alpha3.LogRecordTypeV2 { data, err := log.ToStorage(r, config) if err != nil { return nil, err @@ -184,8 +184,8 @@ func validateData(m *pb.Any) error { return json.Unmarshal(m.GetValue(), &v1beta1.TaskRun{}) case "pipeline.tekton.dev/PipelineRun": return json.Unmarshal(m.GetValue(), &v1beta1.PipelineRun{}) - case "results.tekton.dev/v1alpha2.Log": - return json.Unmarshal(m.GetValue(), &v1alpha2.Log{}) + case "results.tekton.dev/v1alpha3.Log": + return json.Unmarshal(m.GetValue(), &v1alpha3.Log{}) default: // If it's not a well known type, just check that the message is a valid JSON document. return json.Unmarshal(m.GetValue(), &json.RawMessage{}) diff --git a/pkg/apis/v1alpha2/types.go b/pkg/apis/v1alpha3/types.go similarity index 79% rename from pkg/apis/v1alpha2/types.go rename to pkg/apis/v1alpha3/types.go index 8e1c22219..1328d567b 100644 --- a/pkg/apis/v1alpha2/types.go +++ b/pkg/apis/v1alpha3/types.go @@ -1,4 +1,4 @@ -package v1alpha2 +package v1alpha3 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -6,7 +6,10 @@ import ( ) // LogRecordType represents the API resource type for Tekton log records. -const LogRecordType = "results.tekton.dev/v1alpha2.Log" +const LogRecordType = "results.tekton.dev/v1alpha3.Log" + +// LogRecordTypeV2 represents the API resource type for Tekton log records deprecated now. +const LogRecordTypeV2 = "results.tekton.dev/v1alpha2.Log" // Log represents the API resource for Tekton results Log. type Log struct { @@ -49,12 +52,14 @@ const ( // LogStatus defines the current status of the log resource. type LogStatus struct { - Path string `json:"path,omitempty"` - Size int64 `json:"size"` + Path string `json:"path,omitempty"` + Size int64 `json:"size"` + IsStored bool `json:"isStored"` + ErrorOnStoreMsg string `json:"errorOnStoreMsg"` } // Default sets up default values for Log TypeMeta, such as API version and kind. func (t *Log) Default() { t.TypeMeta.Kind = "Log" - t.TypeMeta.APIVersion = "results.tekton.dev/v1alpha2" + t.TypeMeta.APIVersion = "results.tekton.dev/v1alpha3" } diff --git a/pkg/watcher/convert/convert.go b/pkg/watcher/convert/convert.go index a5219bdf5..ef3953d86 100644 --- a/pkg/watcher/convert/convert.go +++ b/pkg/watcher/convert/convert.go @@ -23,7 +23,7 @@ import ( "fmt" "github.com/tektoncd/results/pkg/api/server/v1alpha2/record" - "github.com/tektoncd/results/pkg/apis/v1alpha2" + "github.com/tektoncd/results/pkg/apis/v1alpha3" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -62,14 +62,14 @@ func ToLogProto(in metav1.Object, kind, name string) (*rpb.Any, error) { if err != nil { return nil, err } - log := &v1alpha2.Log{ + log := &v1alpha3.Log{ ObjectMeta: metav1.ObjectMeta{ Namespace: in.GetNamespace(), Name: fmt.Sprintf("%s-log", in.GetName()), UID: types.UID(uid), }, - Spec: v1alpha2.LogSpec{ - Resource: v1alpha2.Resource{ + Spec: v1alpha3.LogSpec{ + Resource: v1alpha3.Resource{ Kind: kind, Namespace: in.GetNamespace(), Name: in.GetName(), @@ -83,7 +83,7 @@ func ToLogProto(in metav1.Object, kind, name string) (*rpb.Any, error) { return nil, err } return &rpb.Any{ - Type: v1alpha2.LogRecordType, + Type: v1alpha3.LogRecordType, Value: b, }, nil } diff --git a/pkg/watcher/convert/convert_test.go b/pkg/watcher/convert/convert_test.go index fc2edfce8..507230bfc 100644 --- a/pkg/watcher/convert/convert_test.go +++ b/pkg/watcher/convert/convert_test.go @@ -22,7 +22,7 @@ import ( "testing" "time" - "github.com/tektoncd/results/pkg/apis/v1alpha2" + "github.com/tektoncd/results/pkg/apis/v1alpha3" "k8s.io/apimachinery/pkg/types" "github.com/google/go-cmp/cmp" @@ -320,7 +320,7 @@ func toJSON(v any) []byte { } func TestToLogProto(t *testing.T) { - wantType := "results.tekton.dev/v1alpha2.Log" + wantType := "results.tekton.dev/v1alpha3.Log" recordName := "foo/results/bar/records/baz" for _, tc := range []struct { in metav1.Object @@ -336,14 +336,14 @@ func TestToLogProto(t *testing.T) { }, } { t.Run(fmt.Sprintf("%s Log", tc.kind), func(t *testing.T) { - log := &v1alpha2.Log{ + log := &v1alpha3.Log{ ObjectMeta: metav1.ObjectMeta{ Namespace: tc.in.GetNamespace(), Name: fmt.Sprintf("%s-log", tc.in.GetName()), UID: types.UID("baz"), }, - Spec: v1alpha2.LogSpec{ - Resource: v1alpha2.Resource{ + Spec: v1alpha3.LogSpec{ + Resource: v1alpha3.Resource{ Kind: tc.kind, Namespace: tc.in.GetNamespace(), Name: tc.in.GetName(),